home *** CD-ROM | disk | FTP | other *** search
/ Education Sampler 1992 [NeXTSTEP] / Education_1992_Sampler.iso / SoundAndMusic / Hyperupic / Hyperupic.app / HyperupicGen.m < prev    next >
Text File  |  1992-08-20  |  29KB  |  1,581 lines

  1. #import "HyperupicGen.h"
  2.  
  3.  
  4. @implementation HyperupicGen
  5.  
  6. + create {
  7.  
  8.     id         newInstance;
  9.  
  10.     newInstance = [ self new ];
  11.     return newInstance;
  12. }
  13.  
  14. - init {
  15.  
  16.     [super init];
  17.     [self setDefaults];
  18.     status = IDLE;    
  19.  
  20.     openReq = [OpenPanel new];
  21.     openMapReq = [OpenPanel new];
  22.     openTableReq = [OpenPanel new];
  23.     saveReq = [SavePanel new];
  24.  
  25.     return self;
  26. }
  27.  
  28. - setDefaults {
  29.  
  30.   interp = 256;
  31.   srate = 44100.;
  32.   pi = 4 * atan(1.);
  33.   twopi = 8 * atan(1.);
  34.   ampref = 1.;
  35.   synt = 0.;
  36.   freqcon = 100.;
  37.   freqdiff = 50.;
  38.   tablesize = Default_Osc_Size;
  39.   x = -1;
  40.   y = -1;
  41.   xstart = -1;
  42.   xend = -1;
  43.   ystart = -1;
  44.   yend = -1;
  45.   srrand(76914020);
  46.   gotImage = NO;
  47.   gotMapFile = NO;
  48.   gotTableFile = NO;
  49.   oscilTable = NO;
  50.   savedSoundFile = YES;
  51.   gotSoundFileName = NO;
  52.   oscInit = NO;
  53.   adjusted = NO;
  54.   strcpy( harmsText, ".7 0 .2 0 .1\0" );
  55.   mapper = @selector(mapRGB);
  56.   dimension = @selector(genNorm);
  57.   display = @selector(displayMinMax);
  58.   coordinate = @selector(setYcoor);
  59.   spread = @selector(genHarmSeries);
  60.   minmax = @selector(mmHarmSeries);
  61.   osctable = @selector(setOscCos);
  62.  
  63.   return self;
  64. }
  65.  
  66. - (float) howFar {
  67.  
  68.   return howfar;
  69. }
  70.  
  71. - (int) xval {
  72.   return x;
  73. }
  74.  
  75. - (int) yval {
  76.   return y;
  77. }
  78.  
  79. - (int) xstartVal {
  80.   return xstart;
  81. }
  82.  
  83. - (int) ystartVal {
  84.   return ystart;
  85. }
  86.  
  87. - (int) xendVal {
  88.   return xend;
  89. }
  90.  
  91. - (int) yendVal {
  92.   return yend;
  93. }
  94.  
  95.  
  96. - setHarmsText: sender {
  97.  
  98.   strcpy( harmsText, [sender stringValue] );
  99.   return self;
  100. }
  101.  
  102. - setxVal: sender {
  103.  
  104.   int grabber;
  105.  
  106.   if ( (grabber = [sender intValue]) > 0 )
  107.  
  108.   xend = x = grabber;
  109.   xstart = 0;
  110.   return self;
  111. }
  112.  
  113. - setyVal: sender {
  114.  
  115.   int grabber;
  116.  
  117.   if ( (grabber = [sender intValue]) > 0 )
  118.  
  119.   yend = y = grabber;
  120.   ystart = 0;
  121.   return self;
  122. }
  123.  
  124. - setxstartVal: sender {
  125.  
  126.   int    grabber;
  127.  
  128.   if ( (grabber = [sender intValue]) > 0 && grabber < x )
  129.   xstart = grabber;
  130.   return self;
  131. }
  132.  
  133. - setystartVal: sender {
  134.  
  135.   int    grabber;
  136.  
  137.   if ( (grabber = [sender intValue]) > 0 && grabber < y )
  138.   ystart = grabber;
  139.   return self;
  140. }
  141.  
  142. - setxendVal: sender {
  143.  
  144.   int    grabber;
  145.  
  146.   if ( (grabber = [sender intValue]) > 0 && grabber < x )
  147.   xend = grabber;
  148.   return self;
  149. }
  150.  
  151. - setyendVal: sender {
  152.  
  153.   int    grabber;
  154.  
  155.   if ( (grabber = [sender intValue]) > 0 && grabber < y )
  156.   yend = grabber;
  157.   return self;
  158. }
  159.  
  160. - (int) getStatus {
  161.  
  162.   return status;
  163. }
  164.  
  165. - (float) getBigee {
  166.  
  167.   return bigee;
  168. }
  169.  
  170. - (float) getDuration {
  171.  
  172.   return duration;
  173. }
  174.  
  175. - (float) adjustFrequency {
  176.  
  177.   if (adjusted == YES) {
  178.     adjusted = NO;
  179.     return (freqcon /= srate / (float) tablesize);
  180.   }
  181.   else {
  182.     adjusted = YES;
  183.     return (freqcon *= srate / (float) tablesize);
  184.   }
  185. }
  186.  
  187. - pause {
  188.  
  189.   status = PAUSED;
  190.   return self;
  191. }
  192.  
  193. - snuff {
  194.  
  195.   status = DYING;
  196.   [self resume];
  197.   return self;
  198. }
  199.  
  200. - resume    //  Gets called from the other thread
  201.  
  202. {
  203.   kern_return_t        ec;
  204.   msg_header_t     msg =   {0,
  205.                          TRUE,
  206.                          sizeof(msg_header_t),
  207.                          MSG_TYPE_NORMAL,
  208.                          0};
  209.  
  210.     if (status == IDLE && appToObjPort != PORT_NULL)
  211.       return nil;
  212.  
  213.     msg.msg_local_port = PORT_NULL;
  214.     msg.msg_remote_port = appToObjPort;
  215.     ec = msg_send(&msg, SEND_TIMEOUT, 0);
  216.  
  217. // huh? (look below)
  218.     if (ec == SEND_TIMED_OUT); 
  219.  
  220.     return self;
  221. }
  222.  
  223.  
  224. - _waitForMessage {    // David Jaffe's pause thread gift
  225.  
  226.   struct {
  227.       msg_header_t header;
  228.       char data[MSG_SIZE_MAX];
  229.   } msg;
  230.  
  231.   status = PAUSED;
  232.  
  233.   (void)port_allocate(task_self(), &appToObjPort);
  234.   msg.header.msg_size = MSG_SIZE_MAX;
  235.   msg.header.msg_local_port = appToObjPort;
  236.   (void)msg_receive(&msg.header, MSG_OPTION_NONE,0);
  237.   (void)port_deallocate(task_self(),appToObjPort);
  238.   appToObjPort = PORT_NULL;
  239.   
  240.   if (status != DYING)
  241.     status = RUNNING;
  242.  
  243.   return self;
  244. }
  245.  
  246. - setXcoor {
  247.  
  248.   N = xend - xstart;
  249.   return self;
  250. }
  251.  
  252. - setYcoor {
  253.  
  254.   N = yend - ystart;
  255.   return self;
  256. }
  257.  
  258. - displayFreqs: sender {
  259.  
  260.   if ( x < 0 || y < 0 ) {
  261.     NXRunAlertPanel("The Beach Boys","Heavens to Murgatroyd! Need coordinates!",
  262.             "okie",NULL,NULL,NULL);
  263.     return nil;
  264.   }
  265.  
  266.   [self perform:display];
  267.   return self;
  268. }
  269.  
  270. - displayAll {
  271.  
  272.   int        i,
  273.         length;
  274.   char        bonk[1024];
  275.   static NXRect wRect = {{120.0, 100.0},{150.0,325.0}};
  276.  
  277.   [self allocateDataspace];
  278.  
  279.   [self perform:coordinate];
  280.   [self perform:spread];
  281.  
  282.   freqDisplay = [[TextView alloc] initFrame:&wRect];
  283.   [[freqDisplay window] setDelegate:self];
  284.   [freqDisplay setTitle:"Frequencies"];
  285.  
  286.   if ( (wRect.origin.x < 20.0) || (wRect.origin.y < 20.0) ) {
  287.     wRect.origin.x = 120.0;
  288.     wRect.origin.y = 100.0;
  289.   }
  290.   else
  291.     NXOffsetRect(&wRect, 20.0, -20.0);
  292.  
  293.   for ( i=0; i < N; i++ ) {
  294.     sprintf(bonk," %3f\n", *(freqs+i));
  295.     length = [freqDisplay textLength];
  296.     [freqDisplay setSel:length :length];
  297.     [freqDisplay replaceSel:bonk];
  298.   }
  299.  
  300.   return self;
  301. }
  302.  
  303. - displayMinMax {
  304.  
  305.   int        length;
  306.   char        bonk[1024];
  307.   static NXRect wRect = {{250.0, 300.0},{200.0,100.0}};
  308.  
  309.   [self perform:coordinate];
  310.   [self perform:minmax];
  311.  
  312.   freqDisplay = [[TextView alloc] initFrame:&wRect];
  313.   [[freqDisplay window] setDelegate:self];
  314.   [freqDisplay setTitle:"Frequency Extrema"];
  315.  
  316.   if ( (wRect.origin.x < 20.0) || (wRect.origin.y < 20.0) ) {
  317.     wRect.origin.x = 120.0;
  318.     wRect.origin.y = 100.0;
  319.   }
  320.   else
  321.     NXOffsetRect(&wRect, 20.0, -20.0);
  322.  
  323.  
  324.     sprintf(bonk,"minimum:\n%6f\n", mm.min);
  325.     length = [freqDisplay textLength];
  326.     [freqDisplay setSel:length :length];
  327.     [freqDisplay replaceSel:bonk];
  328.  
  329.     sprintf(bonk,"\nmaximum:\n%6f\n", mm.max);
  330.     length = [freqDisplay textLength];
  331.     [freqDisplay setSel:length :length];
  332.     [freqDisplay replaceSel:bonk];
  333.  
  334.   return self;
  335. }
  336.  
  337.  
  338. - (char *) getImagePath {
  339.  
  340.   return imageFile;
  341. }
  342.  
  343. - (char *) getMapPath {
  344.  
  345.   return mapFile;
  346. }
  347.  
  348. - (char *) getTablePath {
  349.  
  350.   return tableFile;
  351. }
  352.  
  353.  
  354. - (char *) getSoundPath {
  355.  
  356.   return soundFile;
  357. }
  358.  
  359. - (BOOL) getGotImage {
  360.  
  361.   return gotImage;
  362. }
  363.  
  364. - (BOOL) getGotMapFile {
  365.  
  366.   return gotMapFile;
  367. }
  368.  
  369. - (BOOL) getGotTableFile {
  370.  
  371.   return gotTableFile;
  372. }
  373.  
  374. - (BOOL) getOscilTable {
  375.  
  376.   return oscilTable;
  377. }
  378.  
  379. - (BOOL) getSavedSoundFile {
  380.  
  381.   return savedSoundFile;
  382. }
  383.  
  384. - setImagePath: sender {
  385.  
  386.   strcpy( imageFile, [sender stringValue]);
  387.   [self openImage];
  388.   return self;
  389.  
  390.  
  391. - setMapPath: sender {
  392.  
  393.   strcpy( mapFile, [sender stringValue]);
  394.   [self openMapFile];
  395.   return self;
  396.  
  397. - setTablePath: sender {
  398.  
  399.   strcpy( tableFile, [sender stringValue]);
  400.   [self openTableFile];
  401.   return self;
  402.  
  403. - ampref: sender {
  404.     ampref = [sender doubleValue];
  405.     return self;
  406. }
  407.  
  408. - time: sender {
  409.     interp = [sender intValue];
  410.     return self;
  411. }
  412.  
  413. - freqcon: sender {
  414.     freqcon = (float) [sender doubleValue];
  415.     return self;
  416. }
  417.  
  418. - freqdiff: sender {
  419.     freqdiff = (float) [sender doubleValue];
  420.     return self;
  421. }
  422.  
  423. - samplingRate: sender {
  424.     srate = (float) [sender doubleValue];
  425.     return self;
  426. }
  427.  
  428. - setSeed: sender {
  429.     seed = [sender intValue];
  430.     return self;
  431. }
  432.  
  433. - setSynt: sender {
  434.  
  435.   synt = [sender doubleValue];
  436.   return self;
  437. }
  438.  
  439. - openRequest:sender
  440. {
  441.  
  442.   static const char *const types[] = {NULL, NULL};
  443.  
  444.   [openReq setTitle:"looking for an Image file"];
  445.   if ([openReq runModalForTypes:types]) {
  446.     strcpy(imageFile, [openReq filename]);
  447.     [self openImage];
  448.   }
  449.   return self;
  450. }
  451.  
  452. - openMapRequest:sender
  453. {
  454.   static const char *const types[] = {NULL, NULL};
  455.  
  456.   [openMapReq setTitle:"looking for a Mapping file"];
  457.   if ([openReq runModalForTypes:types]) {
  458.     strcpy(mapFile, [openReq filename]);
  459.     if ( ![self openMapFile] )
  460.       return nil;
  461.   }
  462.   return self;
  463. }
  464.  
  465. - openTableRequest: sender
  466. {
  467.   static const char *const types[] = {NULL, NULL};
  468.  
  469.   [openTableReq setTitle:"looking for an oscillator Table file"];
  470.   if ([openReq runModalForTypes:types]) {
  471.     strcpy(tableFile, [openReq filename]);
  472.     if ( ![self openTableFile] )
  473.       return nil;
  474.   }
  475.   return self;
  476. }
  477.  
  478.  
  479. - saveRequest:sender
  480. {
  481.  
  482.   if (savedSoundFile == YES)
  483.     return self;
  484.  
  485.     if (gotSoundFileName == NO)
  486.       [self saveInRequest:sender];
  487.     else
  488.       [self writeSound];
  489.  
  490.     return self;
  491. }
  492.  
  493. - saveInRequest:sender
  494. {
  495.     
  496.   [saveReq setTitle:"looking to be Saved!"];
  497.   [saveReq setRequiredFileType:""];
  498.   if ( ![saveReq runModal] )
  499.     return nil;
  500.  
  501.   strcpy(soundFile, [saveReq filename]);
  502.   gotSoundFileName = YES;
  503.  
  504.   [self writeSound];
  505.  
  506.   return self;
  507. }
  508.  
  509.  
  510. - openImage {
  511.  
  512.   NXColorSpace    cs;
  513.  
  514.   if (pict != nil) {
  515.     [pict free];
  516.     gotImage = NO;
  517.   }
  518.  
  519.   pict = [[NXBitmapImageRep alloc] initFromFile:imageFile];
  520.  
  521.   if (pict == nil) {
  522.     NXRunAlertPanel("Oral Hygiene",
  523.             "Lame user error.  Couldn't open your imagined file.",
  524.             "okie",NULL,NULL,NULL);
  525.     return nil;
  526.   }
  527.  
  528.   if ( (cs = [pict colorSpace]) != NX_RGBColorSpace ) {
  529.     NXRunAlertPanel("Roman Polanski","Retreat! Your image is not RGB approved!",
  530.                         "okie",NULL,NULL,NULL);
  531.     return nil;
  532.   }
  533.  
  534.   if ( ( [pict bitsPerPixel]) != 24 ) {
  535.     NXRunAlertPanel("Doris Day","Heavens to Murgatroyd!  Use a 24-bit image!",
  536.                        "dokie",NULL,NULL,NULL);
  537.     return nil;
  538.   }
  539.   
  540.   pictdata = [pict data];
  541.   xend = x = [pict pixelsWide];
  542.   yend = y = [pict pixelsHigh];
  543.   xstart = ystart = 0;
  544.  
  545.   gotImage = YES;  
  546.  
  547.   return self;
  548. }
  549.  
  550.  
  551. - openMapFile {
  552.  
  553.   int    i;
  554.   FILE    *fp;
  555.  
  556.   if ( mapFunk.data != NULL ) {
  557.     free( mapFunk.data );
  558.     gotMapFile = NO;
  559.   }
  560.  
  561.   mapFunk.elms = Max_Table_Size;
  562.   mapFunk.data = (float *) space( Max_Table_Size, sizeof(float) );
  563.   
  564.   if ( (fp = fopen( mapFile, "r" )) == NULL ) {
  565.     NXRunAlertPanel("Hamburger Helper","Lame user error. Couldn't open map file.",
  566.             "okie",NULL,NULL,NULL);
  567.     return nil;
  568.   }
  569.   i = 0;
  570.   while ( (fread(mapFunk.data+i, sizeof(float), 1, fp)) != 0 && 
  571.      i < Max_Table_Size )
  572.     ++i;
  573.   mapFunk.elms = (i-1);
  574.  
  575.   gotMapFile = YES;
  576.  
  577.   return self;
  578. }
  579.  
  580.  
  581. - openTableFile {
  582.  
  583.   int    i;
  584.   FILE    *fp;
  585.  
  586.   if ( oscTable.data != NULL ) {
  587.     free( oscTable.data );
  588.     gotTableFile = NO;
  589.   }
  590.  
  591.   oscTable.elms = Max_Osc_Size;
  592.   oscTable.data = (float *) space( Max_Osc_Size, sizeof(float) );
  593.   
  594.   if ( (fp = fopen( tableFile, "r" )) == NULL ) {
  595.     NXRunAlertPanel("The Free Market is Fucked",
  596.             "Egad! Couldn't open oscillator table!",
  597.             "dokie",NULL,NULL,NULL);
  598.     return nil;
  599.   }
  600.   i = 0;
  601.   while ( (fread(oscTable.data+i, sizeof(float), 1, fp)) != 0 && 
  602.      i < Max_Osc_Size )
  603.     ++i;
  604.   oscTable.elms = (i-1);
  605.   oscTable.data = (float *) realloc( oscTable.data, i * sizeof(float) );
  606.  
  607.   if (oscilTable == YES)
  608.     tablesize = i - 1;
  609.  
  610.   gotTableFile = YES;
  611.  
  612.   return self;
  613. }
  614.  
  615.  
  616. - allocSound {
  617.  
  618.   int    width = 2,
  619.     size;
  620.  
  621.   size = interp * maxtime;
  622.   soundPoint = 0;
  623.   bigee = 0.;
  624.   duration = 0.;
  625.  
  626.   if ( sfh != NULL )
  627.     SNDFree(sfh);
  628.  
  629.   SNDAlloc( &sfh, (size*width), SND_FORMAT_LINEAR_16, (int) srate, 1, 0);
  630.   SNDGetDataPointer(sfh, (char **)&soundData, &size, &width );
  631.  
  632.   return self;          
  633. }
  634.  
  635. - writeSound {
  636.  
  637.   int err;
  638.  
  639.   err = SNDWriteSoundfile( soundFile, sfh );
  640.  
  641.   if (err != SND_ERR_NONE) {
  642.     NXRunAlertPanel("Oedipa Maas","Gadzooks! Couldn't write your sound file!",
  643.                         "okie",NULL,NULL,NULL);
  644.     return nil;
  645.   }
  646.   
  647.   if (status == IDLE)
  648.     savedSoundFile = YES;
  649.  
  650.   return self;
  651. }
  652.  
  653. - playSound: sender {
  654.  
  655.   SNDStartPlaying(sfh, 1, 0, 1, NULL, NULL);
  656.   return self;
  657. }
  658.  
  659. - stopPlaying: sender {
  660.  
  661.   SNDStop(1);
  662.   return self;
  663. }
  664.  
  665. - allocateDataspace {
  666.  
  667.     if ( ozone != NULL )
  668.       NXDestroyZone(ozone);
  669.  
  670.     ozone = NXCreateZone( 3 * (N + interp) * 
  671.         sizeof(float), vm_page_size, 0 );
  672.  
  673.     freqs = (float *) zspace( ozone, N+1, sizeof(float) );
  674.     channel = (float *) zspace( ozone, N<<1+1, sizeof(float) );
  675.     output = (float *) zspace( ozone, interp+1, sizeof(float) );
  676.  
  677.     return self;
  678. }
  679.  
  680. - reverseMapping: sender {
  681.  
  682.   int    i,
  683.     elms;
  684.   float    safety;
  685.  
  686.   if (gotMapFile == NO) {
  687.     NXRunAlertPanel("Encephalitis","Lordy Lordy! Load amplitude map file first!",
  688.                         "dokie",NULL,NULL,NULL);
  689.     return nil;
  690.   }
  691.   
  692.   elms = mapFunk.elms;
  693.   for ( i=0; i < (elms>>1); i++ ) {
  694.     safety = *(mapFunk.data+i);
  695.     *(mapFunk.data+i) = *(mapFunk.data+(elms-1)-i);
  696.     *(mapFunk.data+(elms-1)-i) = safety;
  697.   }
  698.  
  699.   return self;
  700. }
  701.  
  702. - runGen {
  703.  
  704.   status = RUNNING;
  705.   oscInit = NO;
  706.   srrand(seed);
  707.   howfar = 0.;
  708.  
  709. // call selected generation method
  710.  
  711.   if ( [self perform:dimension] ) {
  712.     SNDStop(1);
  713.     NXBeep();
  714.   }
  715.   status = IDLE;
  716.  
  717.   return self;
  718. }
  719.  
  720. - genNorm {
  721.  
  722.   int    cnt;
  723.  
  724.   N = yend - ystart;        // set number of frequency amplitude pairs
  725.   ampscale = ampref / (float) N;
  726.   maxtime = xend;
  727.   [self allocSound];
  728.   savedSoundFile = NO;
  729.   [self allocateDataspace];
  730.   [self perform:spread];    // create frequency axis values
  731.  
  732. // main loop (iterate for each value of axis)
  733.   
  734.   for ( timedim = xstart; timedim < maxtime; timedim++ ) {
  735.  
  736.     timeinc = timedim * Bytes_Per_Pixel;
  737.     // check for death or pause
  738.     if (status > 2)  {
  739.       if (status == PAUSED)
  740.     [self _waitForMessage];
  741.       else {
  742.     if (status == DYING)
  743.       return nil;
  744.       }
  745.     }
  746.  
  747. // increment along time axis
  748.  
  749.     cnt = (N-1);
  750.     for ( freqdim = ystart; freqdim < yend; freqdim++ ) {
  751.       datainc = cnt * x * Bytes_Per_Pixel;
  752.       *(channel+(freqdim<<1)+1) = *(freqs+freqdim);
  753.       [self perform:mapper];
  754.       cnt--;
  755.     }
  756.  
  757.     if ( ![self oscbank] )
  758.       return nil;
  759.  
  760.     [self writeoutput];
  761.     howfar = ((float) timedim - xstart) / ((float) maxtime - xstart);
  762.   }
  763.   return self;
  764. }
  765.  
  766. - genRotNorm {
  767.  
  768.   int    cnt;
  769.  
  770.   N = xend - xstart;        // set number of frequency amplitude pairs  
  771.   ampscale = ampref / (float) N;
  772.   maxtime = yend;
  773.   [self allocSound];
  774.   savedSoundFile = NO;
  775.   [self allocateDataspace];
  776.   [self perform:spread];    // create frequency axis values
  777.  
  778. // main loop (iterate for each value of axis)
  779.   
  780.   for ( timedim = (ystart * x * Bytes_Per_Pixel); 
  781.     timedim < (maxtime * x * Bytes_Per_Pixel); 
  782.     timedim += (x * Bytes_Per_Pixel) ) {
  783.  
  784.     timeinc = timedim;
  785.     // check for death or pause
  786.     if (status > 2)  {
  787.       if (status == PAUSED)
  788.     [self _waitForMessage];
  789.       else {
  790.     if (status == DYING)
  791.       return nil;
  792.       }
  793.     }
  794.  
  795. // increment along time axis
  796.  
  797.     cnt = 0;
  798.     for ( freqdim = xstart; freqdim < xend; freqdim++ ) {
  799.       datainc = freqdim * Bytes_Per_Pixel;
  800.       *(channel+(freqdim<<1)+1) = *(freqs+freqdim);
  801.       [self perform:mapper];
  802.       cnt++;
  803.     }
  804.  
  805.     if ( ![self oscbank] )
  806.       return nil;
  807.  
  808.     [self writeoutput];
  809.     howfar = ( (float) (timedim / (x * Bytes_Per_Pixel)) - ystart ) 
  810.         / ((float) maxtime - ystart);
  811.   }
  812.  
  813.   return self;
  814. }
  815.  
  816. - genRetro {
  817.  
  818.   int    cnt;
  819.  
  820.   N = yend - ystart;        // set number of frequency amplitude pairs
  821.   ampscale = ampref / (float) N;
  822.   maxtime = xend;
  823.   [self allocSound];
  824.   savedSoundFile = NO;
  825.   [self allocateDataspace];
  826.   [self perform:spread];    // create frequency axis values
  827.  
  828. // main loop (iterate for each value of axis)
  829.   
  830.   for ( timedim=(maxtime-1); timedim >= xstart; timedim-- ) {
  831.  
  832.     timeinc = timedim * Bytes_Per_Pixel;    
  833.     // check for death or pause
  834.     if (status > 2)  {
  835.       if (status == PAUSED)
  836.     [self _waitForMessage];
  837.       else {
  838.     if (status == DYING)
  839.       return nil;
  840.       }
  841.     }
  842.  
  843. // increment along time axis
  844.  
  845.     cnt = (N-1);
  846.     for ( freqdim = ystart; freqdim < yend; freqdim++ ) {
  847.       datainc = cnt * x * Bytes_Per_Pixel;
  848.       *(channel+(freqdim<<1)+1) = *(freqs+freqdim);
  849.       [self perform:mapper];
  850.       cnt--;
  851.     }
  852.  
  853.     if ( ![self oscbank] )
  854.       return nil;
  855.  
  856.     [self writeoutput];
  857.  
  858.     howfar = ( (float) (maxtime-1) - timedim ) / 
  859.               ((float) (maxtime-1) - xstart);
  860.   }
  861.   return self;
  862. }
  863.  
  864. - genRotRetro {
  865.  
  866.   int    cnt;
  867.  
  868.   N = xend - xstart;        // set number of frequency amplitude pairs  
  869.   ampscale = ampref / (float) N;
  870.   maxtime = yend;
  871.   [self allocSound];
  872.   savedSoundFile = NO;
  873.   [self allocateDataspace];
  874.   [self perform:spread];    // create frequency axis values
  875.  
  876. // main loop (iterate for each value of axis)
  877.   
  878.   for ( timedim = ( (maxtime-1) * x * Bytes_Per_Pixel); 
  879.     timedim >= ystart * x * Bytes_Per_Pixel;
  880.     timedim -= (x * Bytes_Per_Pixel) ) {
  881.  
  882.     timeinc = timedim;
  883.     // check for death or pause
  884.     if (status > 2)  {
  885.       if (status == PAUSED)
  886.     [self _waitForMessage];
  887.       else {
  888.     if (status == DYING)
  889.       return nil;
  890.       }
  891.     }
  892.  
  893. // increment along time axis
  894.  
  895.     cnt = 0;
  896.     for ( freqdim = xstart; freqdim < xend; freqdim++ ) {
  897.       datainc = freqdim * Bytes_Per_Pixel;
  898.       *(channel+(freqdim<<1)+1) = *(freqs+freqdim);
  899.       [self perform:mapper];
  900.       cnt++;
  901.     }
  902.  
  903.     if ( ![self oscbank] )
  904.       return nil;
  905.  
  906.     [self writeoutput];
  907.     howfar = ( (float) (maxtime-1) - (timedim / (x * Bytes_Per_Pixel)) )
  908.               / ((float) (maxtime-1) - ystart);
  909.   }
  910.  
  911.   return self;
  912. }
  913.  
  914.  
  915. - genNormInv {
  916.  
  917.   int    cnt;
  918.  
  919.   N = yend - ystart;         // set number of frequency amplitude pairs
  920.   ampscale = ampref / (float) N;
  921.   maxtime = xend;
  922.   [self allocSound];
  923.   savedSoundFile = NO;
  924.   [self allocateDataspace];
  925.   [self perform:spread];    // create frequency axis values
  926.  
  927. // main loop (iterate for each value of axis)
  928.   
  929.   for ( timedim=xstart; timedim < maxtime; timedim++ ) {
  930.  
  931.     timeinc = timedim * Bytes_Per_Pixel;
  932.     // check for death or pause
  933.     if (status > 2)  {
  934.       if (status == PAUSED)
  935.     [self _waitForMessage];
  936.       else {
  937.     if (status == DYING)
  938.       return nil;
  939.       }
  940.     }
  941.  
  942. // increment along time axis
  943.  
  944.     cnt = (N-1);
  945.     for ( freqdim = ystart; freqdim < yend; freqdim++ ) {
  946.       datainc = cnt * x * Bytes_Per_Pixel;
  947.       *(channel+(freqdim<<1)+1) = *(freqs+cnt);
  948.       [self perform:mapper];
  949.       cnt--;
  950.     }
  951.  
  952.     if ( ![self oscbank] )
  953.       return nil;
  954.  
  955.     [self writeoutput];
  956.     howfar = ( (float) timedim - xstart ) / ((float) maxtime - xstart);
  957.   }
  958.   return self;
  959. }
  960.  
  961. - genRotNormInv {
  962.  
  963.   int    cnt;
  964.  
  965.   N = xend - xstart;        // set number of frequency amplitude pairs  
  966.   ampscale = ampref / (float) N;
  967.   maxtime = yend;
  968.   [self allocSound];
  969.   savedSoundFile = NO;
  970.   [self allocateDataspace];
  971.   [self perform:spread];    // create frequency axis values
  972.  
  973. // main loop (iterate for each value of axis)
  974.   
  975.   for ( timedim = (ystart * x * Bytes_Per_Pixel);
  976.        timedim < (maxtime * x * Bytes_Per_Pixel); 
  977.        timedim += (x * Bytes_Per_Pixel) ) {
  978.  
  979.     timeinc = timedim;
  980.     // check for death or pause
  981.     if (status > 2)  {
  982.       if (status == PAUSED)
  983.     [self _waitForMessage];
  984.       else {
  985.     if (status == DYING)
  986.       return nil;
  987.       }
  988.     }
  989.  
  990. // increment along time axis
  991.  
  992.     cnt = 0;
  993.     for ( freqdim = xstart; freqdim < xend; freqdim++ ) {
  994.       datainc = freqdim * Bytes_Per_Pixel;
  995.       *(channel+(freqdim<<1)+1) = *(freqs + ( (x-1) - freqdim ));
  996.       [self perform:mapper];
  997.       cnt++;
  998.     }
  999.  
  1000.     if ( ![self oscbank] )
  1001.       return nil;
  1002.  
  1003.     [self writeoutput];
  1004.     howfar = ( ((float) timedim / (x * Bytes_Per_Pixel)) - ystart ) /
  1005.               ((float) maxtime - ystart);
  1006.   }
  1007.  
  1008.   return self;
  1009. }
  1010.  
  1011. - genRetroInv {
  1012.  
  1013.   int    cnt;
  1014.  
  1015.   N = yend - ystart;        // set number of frequency amplitude pairs
  1016.   ampscale = ampref / (float) N;
  1017.   maxtime = xend;
  1018.   [self allocSound];
  1019.   savedSoundFile = NO;
  1020.   [self allocateDataspace];
  1021.   [self perform:spread];    // create frequency axis values
  1022.  
  1023. // main loop (iterate for each value of axis)
  1024.   
  1025.   for ( timedim=(maxtime-1); timedim >= xstart; timedim-- ) {
  1026.  
  1027.     timeinc = timedim * Bytes_Per_Pixel;
  1028.     // check for death or pause
  1029.     if (status > 2)  {
  1030.       if (status == PAUSED)
  1031.     [self _waitForMessage];
  1032.       else {
  1033.     if (status == DYING)
  1034.       return nil;
  1035.       }
  1036.     }
  1037.  
  1038. // increment along time axis
  1039.  
  1040.     cnt = (N-1);
  1041.     for ( freqdim = ystart; freqdim < yend; freqdim++ ) {
  1042.       datainc = cnt * x * Bytes_Per_Pixel;
  1043.       *(channel+(freqdim<<1)+1) = *(freqs+cnt);
  1044.       [self perform:mapper];
  1045.       cnt--;
  1046.     }
  1047.  
  1048.  
  1049.     if ( ![self oscbank] )
  1050.       return nil;
  1051.  
  1052.     [self writeoutput];
  1053.     howfar = ( (float) (maxtime-1) - timedim ) / 
  1054.         ((float) (maxtime-1) - xstart);
  1055.   }
  1056.   return self;
  1057. }
  1058.  
  1059. - genRotRetroInv {
  1060.  
  1061.   int    cnt;
  1062.  
  1063.   N = xend - xstart;        // set number of frequency amplitude pairs  
  1064.   ampscale = ampref / (float) N;
  1065.   maxtime = yend;
  1066.   [self allocSound];
  1067.   savedSoundFile = NO;
  1068.   [self allocateDataspace];
  1069.   [self perform:spread];    // create frequency axis values
  1070.  
  1071. // main loop (iterate for each value of axis)
  1072.   
  1073.   for ( timedim = ( (maxtime-1) * x * Bytes_Per_Pixel);
  1074.        timedim >= ystart * x * Bytes_Per_Pixel;
  1075.        timedim -= (x * Bytes_Per_Pixel) ) {
  1076.  
  1077.     timeinc = timedim;
  1078.     // check for death or pause
  1079.     if (status > 2)  {
  1080.       if (status == PAUSED)
  1081.     [self _waitForMessage];
  1082.       else {
  1083.     if (status == DYING)
  1084.       return nil;
  1085.       }
  1086.     }
  1087.  
  1088. // increment along time axis
  1089.  
  1090.     cnt = 0;
  1091.     for ( freqdim = xstart; freqdim < xend; freqdim++ ) {
  1092.       datainc = freqdim * Bytes_Per_Pixel;
  1093.       *(channel+(freqdim<<1)+1) = *(freqs + ( (x-1) - freqdim ));
  1094.       [self perform:mapper];
  1095.       cnt++;
  1096.     }
  1097.  
  1098.     if ( ![self oscbank] )
  1099.       return nil;
  1100.  
  1101.     [self writeoutput];
  1102.     howfar = ( (float) (maxtime-1) - (timedim / (x * Bytes_Per_Pixel)) )
  1103.           / ((float) maxtime - ystart);
  1104.   }
  1105.  
  1106.   return self;
  1107. }
  1108.  
  1109.  
  1110. - genHarmSeries {
  1111.  
  1112.   int    i;
  1113.  
  1114.   for ( i=0; i<N; i++ )
  1115.     *(freqs+i) = freqcon + (freqdiff * i);
  1116.  
  1117.   return self;
  1118. }
  1119.  
  1120. - genScale {
  1121.  
  1122.   int    i;
  1123.  
  1124.   *freqs = freqcon;
  1125.   for ( i=1; i<N; i++ )
  1126.     *(freqs+i) = *(freqs+i-1) * freqdiff;
  1127.  
  1128.   return self;
  1129. }
  1130.  
  1131. - mmHarmSeries {
  1132.  
  1133.   mm.min = freqcon;
  1134.   mm.max = (N-1) * freqdiff + freqcon;
  1135.   return self;
  1136. }
  1137.  
  1138. - mmScale {
  1139.  
  1140.   mm.min = freqcon;
  1141.   mm.max = pow(freqdiff, (N-1)) * freqcon;
  1142.   return self;
  1143. }
  1144.  
  1145. - mapRGB {
  1146.  
  1147.   static float    scaler = 766.0;
  1148.  
  1149.   *(channel+(freqdim<<1)) = *(mapFunk.data + (int) ( ( (float) ( 
  1150.     (int) ( *(pictdata+datainc+timeinc) ) + 
  1151.     (int) ( *(pictdata+datainc+timeinc+1) ) +
  1152.     (int) ( *(pictdata+datainc+timeinc+2) )) / scaler ) * 
  1153.     (float) mapFunk.elms ));
  1154.  
  1155.   return self;
  1156. }
  1157.  
  1158. - mapR {
  1159.  
  1160.   static float    scaler = 256.0;
  1161.  
  1162.   *(channel+(freqdim<<1)) = *(mapFunk.data + (int) ( ( (float) ( 
  1163.     (int) ( *(pictdata+datainc+timeinc) )) / scaler ) * 
  1164.     (float) mapFunk.elms ));
  1165.  
  1166.   return self;
  1167. }
  1168.  
  1169. - mapG {
  1170.  
  1171.   static float    scaler = 256.0;
  1172.  
  1173.   *(channel+(freqdim<<1)) = *(mapFunk.data + (int) ( ( (float) ( 
  1174.     (int) ( *(pictdata+datainc+timeinc+1) )) / scaler ) * 
  1175.     (float) mapFunk.elms ));
  1176.  
  1177.   return self;
  1178. }
  1179.  
  1180. - mapB {
  1181.  
  1182.   static float    scaler = 256.0;
  1183.  
  1184.   *(channel+(freqdim<<1)) = *(mapFunk.data + (int) ( ( (float) ( 
  1185.     (int) ( *(pictdata+datainc+timeinc+2) )) / scaler ) * 
  1186.     (float) mapFunk.elms ));
  1187.  
  1188.   return self;
  1189. }
  1190.  
  1191. - mapRG {
  1192.  
  1193.   static float    scaler = 511.0;
  1194.  
  1195.   *(channel+(freqdim<<1)) = *(mapFunk.data + (int) ( ( (float) ( 
  1196.     (int) ( *(pictdata+datainc+timeinc) ) + 
  1197.     (int) ( *(pictdata+datainc+timeinc+1) )) / scaler ) * 
  1198.     (float) mapFunk.elms ));
  1199.  
  1200.   return self;
  1201. }
  1202.  
  1203. - mapRB {
  1204.  
  1205.   static float    scaler = 511.0;
  1206.  
  1207.   *(channel+(freqdim<<1)) = *(mapFunk.data + (int) ( ( (float) ( 
  1208.     (int) ( *(pictdata+datainc+timeinc) ) + 
  1209.     (int) ( *(pictdata+datainc+timeinc+2) )) / scaler ) * 
  1210.     (float) mapFunk.elms ));
  1211.  
  1212.   return self;
  1213. }
  1214.  
  1215. - mapGB {
  1216.  
  1217.   static float    scaler = 511.0;
  1218.  
  1219.   *(channel+(freqdim<<1)) = *(mapFunk.data + (int) ( ( (float) ( 
  1220.     (int) ( *(pictdata+datainc+timeinc+1) ) +
  1221.     (int) ( *(pictdata+datainc+timeinc+2) )) / scaler ) * 
  1222.     (float) mapFunk.elms ));
  1223.  
  1224.   return self;
  1225. }
  1226.  
  1227. - selectGenHarmSeries: sender {
  1228.  
  1229.   spread = @selector(genHarmSeries);
  1230.   minmax = @selector(mmHarmSeries);
  1231.   return self;
  1232. }
  1233.  
  1234. - selectGenScale: sender {
  1235.  
  1236.   spread = @selector(genScale);
  1237.   minmax = @selector(mmScale);
  1238.   return self;
  1239. }
  1240.  
  1241. - selectDisplayAll: sender {
  1242.  
  1243.   display = @selector(displayAll);
  1244.   return self;
  1245. }
  1246.  
  1247. - selectDisplayMinMax: sender {
  1248.  
  1249.   display = @selector(displayMinMax);
  1250.   return self;
  1251. }
  1252.  
  1253. - selectXcoor: sender {
  1254.   
  1255.   coordinate = @selector(setXcoor);
  1256.   return self;
  1257. }
  1258.  
  1259. - selectYcoor: sender {
  1260.   
  1261.   coordinate = @selector(setYcoor);
  1262.   return self;
  1263. }
  1264.  
  1265.  
  1266. - selectGenNorm: sender {
  1267.  
  1268.   dimension = @selector(genNorm);
  1269.   return self;
  1270. }
  1271.  
  1272. - selectGenRetro: sender {
  1273.  
  1274.   dimension = @selector(genRetro);
  1275.   return self;
  1276. }
  1277.  
  1278. - selectGenRotNorm: sender {
  1279.  
  1280.   dimension = @selector(genRotNorm);
  1281.   return self;
  1282. }
  1283.  
  1284. - selectGenRotRetro: sender {
  1285.  
  1286.   dimension = @selector(genRotRetro);
  1287.   return self;
  1288. }
  1289.  
  1290. - selectGenNormInv: sender {
  1291.  
  1292.   dimension = @selector(genNormInv);
  1293.   return self;
  1294. }
  1295.  
  1296. - selectGenRetroInv: sender {
  1297.  
  1298.   dimension = @selector(genRetroInv);
  1299.   return self;
  1300. }
  1301.  
  1302. - selectGenRotNormInv: sender {
  1303.  
  1304.   dimension = @selector(genRotNormInv);
  1305.   return self;
  1306. }
  1307.  
  1308. - selectGenRotRetroInv: sender {
  1309.  
  1310.   dimension = @selector(genRotRetroInv);
  1311.   return self;
  1312. }
  1313.  
  1314. - selectMapR: sender {
  1315.  
  1316.   mapper = @selector(mapR);
  1317.   return self;
  1318. }
  1319.  
  1320. - selectMapG: sender {
  1321.  
  1322.   mapper = @selector(mapG);
  1323.   return self;
  1324. }
  1325.  
  1326. - selectMapB: sender {
  1327.  
  1328.   mapper = @selector(mapB);
  1329.   return self;
  1330. }
  1331.  
  1332. - selectMapRG: sender {
  1333.  
  1334.   mapper = @selector(mapRG);
  1335.   return self;
  1336. }
  1337.  
  1338. - selectMapRB: sender {
  1339.  
  1340.   mapper = @selector(mapRB);
  1341.   return self;
  1342. }
  1343.  
  1344. - selectMapGB: sender {
  1345.  
  1346.   mapper = @selector(mapGB);
  1347.   return self;
  1348. }
  1349.  
  1350. - selectMapRGB: sender {
  1351.  
  1352.   mapper = @selector(mapRGB);
  1353.   return self;
  1354. }
  1355.  
  1356. - writeoutput
  1357. {
  1358.   int   i;
  1359.  
  1360.   for ( i=0; i < interp; i++ ) {
  1361.     if (fabs( (*(output+i) *= ampscale) ) > bigee)
  1362.       bigee = fabs( *(output+i) );
  1363.     *(soundData + soundPoint + i) = (short) (32767. * *(output+i));
  1364.   }
  1365.   soundPoint += interp;
  1366.   duration = (float) soundPoint / srate;
  1367.  
  1368.   return self;
  1369. }
  1370.  
  1371. - selectOscCos: sender {
  1372.  
  1373.   if (status != IDLE)
  1374.     return nil;
  1375.  
  1376.   oscilTable = NO;
  1377.   tablesize = Default_Osc_Size;
  1378.   osctable = @selector(setOscCos);
  1379.   return self;
  1380. }
  1381.  
  1382.  
  1383. - selectOscComplex: sender {
  1384.  
  1385.   int    i,
  1386.       grabber;
  1387.  
  1388.   float    hoax;
  1389.   char    *doink;
  1390.  
  1391.   if (status != IDLE)
  1392.     return nil;
  1393.  
  1394.   oscilTable = NO;
  1395.  
  1396.   doink = (char *) space( 8192, sizeof(char) );
  1397.  
  1398.   strcpy( doink, harmsText );
  1399.  
  1400.   harms.data = (float *) space( Max_Harm, sizeof(float) );
  1401.   tablesize = Default_Osc_Size;
  1402.  
  1403.   i = 0;
  1404.   while ( i < Max_Harm ) {
  1405.     if ( (grabber = sscanf(doink, "%f", &hoax)) == 0 || grabber == EOF)
  1406.       break;
  1407.     *(harms.data+i) = hoax;
  1408.     ++i;
  1409.     if ( (doink = index( doink, ' ' )) == NULL )
  1410.       break;
  1411.     while ( isspace(*doink) )
  1412.       doink++;
  1413.   } 
  1414.   harms.elms = i;
  1415.  
  1416.   osctable = @selector(setOscComplex);
  1417.  
  1418.   return self;
  1419. }
  1420.  
  1421. - selectOscTable: sender {
  1422.  
  1423.   if (status != IDLE)
  1424.     return nil;
  1425.  
  1426.   tablesize = oscTable.elms - 1;
  1427.   oscilTable = YES;
  1428.   osctable = @selector(setOscTable);
  1429.   return self;
  1430. }
  1431.  
  1432. - setOscCos {
  1433.  
  1434.   int    i;
  1435.   float twopioL = twopi / tablesize;
  1436.  
  1437.   for ( i = 0; i < tablesize+1; i++ )
  1438.     *(table+i) = cos( twopioL*i );
  1439.  
  1440.   return self;
  1441. }
  1442.  
  1443. - setOscComplex {
  1444.  
  1445.   int    i,j;
  1446.   float twopioL = twopi / tablesize;
  1447.  
  1448.   for ( i=0; i < tablesize+1; i++ )
  1449.     *(table+i) = cos( twopioL*i );
  1450.  
  1451.   for ( j=2; j <= harms.elms; j++ ) {
  1452.     for ( i=0; i < tablesize+1; i++ )
  1453.       *(table+i) += cos( j*twopioL*i );
  1454.   }
  1455.  
  1456.   return self;
  1457. }
  1458.  
  1459. - setOscTable {
  1460.  
  1461.   int    i;
  1462.  
  1463.   if (gotTableFile == NO) {
  1464.     return nil;
  1465.   }
  1466.  
  1467.   tablesize = oscTable.elms - 1;
  1468.  
  1469.   for ( i=0; i < tablesize+1; i++ )
  1470.     *(table+i) = *(oscTable.data + i);
  1471.  
  1472.   return self;
  1473. }
  1474.  
  1475.  
  1476. - oscbank
  1477. {
  1478.  
  1479.   static float     Iinv,
  1480.         *lastamp,
  1481.         *lastfreq,
  1482.         *index,
  1483.            Pinc;
  1484.   int         i,j,
  1485.         amp,
  1486.         freq;
  1487.  
  1488. /* first pass: allocate memory to hold previous values
  1489.    of amplitude and frequency for each channel, the table
  1490.    index for each oscillator, and the table itself; also
  1491.    compute constants */
  1492.  
  1493.   if ( oscInit == NO ) {
  1494.  
  1495.     if ( funzone != NULL )
  1496.       NXDestroyZone(funzone);
  1497.  
  1498.     if (oscilTable == YES)
  1499.       tablesize = oscTable.elms - 1;
  1500.     
  1501.     funzone = NXCreateZone( 3 * (N + interp) * 
  1502.                sizeof(float), vm_page_size, 0 );
  1503.     
  1504.     lastamp = (float *) zspace( funzone, N+1, sizeof(float) );
  1505.     lastfreq = (float *) zspace( funzone, N+1, sizeof(float) );
  1506.     index = (float *) zspace( funzone, N+1, sizeof(float) );
  1507.     table = (float *) zspace( funzone, tablesize+1, sizeof(float) );
  1508.     
  1509.     for ( i = 0; i < N+1; i++ ) {
  1510.       *(lastamp+i) = *(lastfreq+i) = 0.;
  1511.       *(index+i) = prand() * (float) tablesize;
  1512.     }
  1513.  
  1514.     if ( ![self perform:osctable] )
  1515.       return nil;
  1516.  
  1517.     Iinv = 1. / interp;
  1518.     Pinc = ( (float) tablesize ) / srate;
  1519.  
  1520.     oscInit = YES;
  1521.   }
  1522.  
  1523.   for ( i = 0; i < interp; i++ )
  1524.     *(output+i) = 0.;
  1525.  
  1526. /* for each channel, compute I samples using linear
  1527.    interpolation on the amplitude and frequency
  1528.    control values */
  1529.  
  1530.     for ( i=0; i < N; i++ ) {
  1531.  
  1532.       register float     a,
  1533.             ainc,
  1534.             f,
  1535.             finc,
  1536.             address;
  1537.  
  1538.       freq = ( amp = ( i << 1 ) ) + 1;
  1539.       if ( *(channel+amp) < synt )     /* skip the little ones */
  1540.     continue;
  1541.  
  1542.       *(channel+freq) *= Pinc;
  1543.       finc = ( *(channel+freq) - ( f = *(lastfreq+i) ) ) * Iinv;
  1544.       
  1545.       ainc = ( *(channel+amp) - ( a = *(lastamp+i) ) ) * Iinv;
  1546.       address = *(index+i);
  1547.       
  1548. /* accumulate the I samples from each oscillator into
  1549.    output array O (initially assumed to be zero);
  1550.    f is frequency in Hz scaled by oscillator increment
  1551.    factor and pitch (Pinc); a is amplitude; */
  1552.  
  1553.       for ( j=0; j < interp; j++ ) {
  1554.     *(output+j) += a * *(table + ( (int) address ));
  1555.     address += f;
  1556.     
  1557.     while ( address >= (float) tablesize )
  1558.       address -= (float) tablesize;
  1559.     
  1560.     while ( address < 0. )
  1561.       address += (float) tablesize;
  1562.     
  1563.     a += ainc;
  1564.     f += finc;
  1565.       } 
  1566.  
  1567. /* save current values for next iteration */
  1568.  
  1569.       *(lastfreq+i) = *(channel+freq);
  1570.       *(lastamp+i) = *(channel+amp);
  1571.       *(index+i) = address;
  1572.     }
  1573.  
  1574.     return self;
  1575. }
  1576.  
  1577. @end
  1578.