home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.mdf / SourceCode / MiscKit1.2.6 / Palettes / MiscSoundPalette / MiscSoundUtil.subproj / MiscVolumeMeter.m < prev    next >
Encoding:
Text File  |  1994-05-27  |  13.7 KB  |  678 lines

  1.  
  2. #import "MiscVolumeMeter.h"
  3. #import <stdio.h>
  4.  
  5. @implementation MiscVolumeMeter
  6.  
  7. // slave method to the below timed entry function
  8.  
  9. - _update
  10.     {
  11.     if ([delegate respondsTo:@selector(meterWillUpdateOnOwn:)])
  12.         [delegate meterWillUpdateOnOwn:self];
  13.     return [self display];
  14.     }
  15.  
  16.  
  17. // timed entry procedure for periodically updating
  18.  
  19. DPSTimedEntryProc VOLUMEMETER_update_meter
  20.     (DPSTimedEntry teNum,double now, void* the_meter)
  21.     {
  22.     MiscVolumeMeter* temp_meter=(MiscVolumeMeter*) the_meter;
  23.     //printf ("Display!\n");
  24.     [temp_meter _update];
  25.     return (void*) NULL;
  26.     }
  27.  
  28.  
  29. // convenience functions
  30.  
  31. BOOL VOLUMEMETER_draw_wide(const NXRect* aRect)
  32.     {
  33.     return (BOOL) (aRect->size.width>=aRect->size.height);
  34.     }
  35.  
  36. BOOL VOLUMEMETER_can_draw(const NXRect* aRect)
  37.     {
  38.     return (BOOL) (aRect->size.width>VOLUMEMETER_VALUE_INSET*2
  39.         &&aRect->size.height>VOLUMEMETER_VALUE_INSET*2);
  40.     }
  41.  
  42.  
  43.  
  44. // methods
  45.  
  46. - initFrame:(const NXRect*) frameRect
  47.     {
  48.     int x;
  49.     
  50.     [super initFrame:frameRect];
  51.     
  52.     delegate=NULL;
  53.     input=NO;
  54.     running=NO;
  55.     bezeled=YES;
  56.     peak_bubble_displayed=YES;
  57.     stereo=YES;
  58.     background_gray=NX_DKGRAY;
  59.     value_gray=NX_LTGRAY;
  60.     bubble_gray=NX_WHITE;
  61.     refresh=VOLUMEMETER_TIMED_ENTRY_SPEED;
  62.     refreshes_per_new_peak_bubble=VOLUMEMETER_STD_REFRESHES;
  63.     refresh_tally=0;
  64.     for (x=0;x<VOLUMEMETER_MAX_REFRESHES;x++) 
  65.         {refreshes_left[x]=0.0;refreshes_right[x]=0.0;}
  66.     current_max_refresh_left=0;
  67.     current_max_refresh_right=0;
  68.     
  69.     if (input_device==NULL) input_device= [[NXSoundIn alloc] init];
  70.     if (output_device==NULL) output_device=[[NXSoundOut alloc] init];
  71.     [input_device setDetectPeaks:YES];
  72.     [output_device setDetectPeaks:YES];
  73.     teNum=0;
  74.     
  75.     return self;
  76.     }
  77.     
  78.     
  79.  
  80. - drawSelf:(const NXRect*) rects:(int) rectCount
  81.     {
  82.     NXRect drawRectLeft,drawRectRight;
  83.     NXRect backgroundRect=bounds;
  84.     NXRect valueRect=bounds;
  85.     float left,right;
  86.     int just_erase=0;
  87.     
  88.     //if (![window isVisible]) return NULL;        // no window to draw in.
  89.     // the above has been turned off because when loading Resound,
  90.     // the sound meter wouldn't display until a sound was being played
  91.     // or recorded!
  92.     
  93.     if ([delegate respondsTo:@selector(meterWillUpdate:)])
  94.         [delegate meterWillUpdate:self];
  95.     
  96.     // first to check to see if the sound lock is current
  97.     //printf ("Meter\n");
  98.     if (sound!=NULL)
  99.         {
  100.         int status=NX_SoundStopped;
  101.         id actual_sound=NULL;            // quiets compiler complaints
  102.         
  103.         if ([sound isKindOf:[Sound class]]) 
  104.             {actual_sound=sound;}
  105.         else if ([sound isKindOf:[SoundView class]])
  106.             {actual_sound=[sound soundBeingProcessed];}
  107.         status=[actual_sound status];
  108.         if (status==NX_SoundStopped||
  109.             status==NX_SoundInitialized||
  110.             status==NX_SoundFreed) 
  111.         {just_erase=1;}
  112.             
  113.         // Then modify the meter to match the sound    
  114.         
  115.         else if (status==NX_SoundRecordingPaused||
  116.                  status==NX_SoundRecording||
  117.                  status==NX_SoundRecordingPending)
  118.         {[self setToInput];}
  119.         
  120.         else if (status==NX_SoundPlayingPaused||
  121.                  status==NX_SoundPlaying||
  122.                  status==NX_SoundPlayingPending)
  123.         {[self setToOutput];}
  124.         
  125.         if ([actual_sound channelCount]>1)
  126.             {[self setStereo];}
  127.         else {[self setMono];}
  128.         }
  129.     
  130.     // then check for bezeled stuff
  131.     
  132.     
  133.     if (bezeled)
  134.         {
  135.         backgroundRect.origin.x        +=VOLUMEMETER_BACKGROUND_INSET; 
  136.         backgroundRect.size.width    -=VOLUMEMETER_BACKGROUND_INSET*2;
  137.         backgroundRect.origin.y        +=VOLUMEMETER_BACKGROUND_INSET; 
  138.         backgroundRect.size.height    -=VOLUMEMETER_BACKGROUND_INSET*2;
  139.         
  140.         valueRect.origin.x        +=VOLUMEMETER_VALUE_INSET;
  141.         valueRect.size.width     -=VOLUMEMETER_VALUE_INSET*2;
  142.         valueRect.origin.y        +=VOLUMEMETER_VALUE_INSET;
  143.         valueRect.size.height    -=VOLUMEMETER_VALUE_INSET*2;
  144.         }
  145.     else
  146.         {
  147.         valueRect.origin.x        +=
  148.                 VOLUMEMETER_VALUE_INSET-VOLUMEMETER_BACKGROUND_INSET;
  149.         valueRect.size.width     -=
  150.                 VOLUMEMETER_VALUE_INSET*2-VOLUMEMETER_BACKGROUND_INSET*2;
  151.         valueRect.origin.y        +=
  152.                 VOLUMEMETER_VALUE_INSET-VOLUMEMETER_BACKGROUND_INSET;
  153.         valueRect.size.height    -=
  154.                 VOLUMEMETER_VALUE_INSET*2-VOLUMEMETER_BACKGROUND_INSET*2;
  155.         }
  156.     
  157.     if (!VOLUMEMETER_can_draw(&bounds)) return self;    // can't draw
  158.     
  159.     if (bezeled) NXDrawGrayBezel(&bounds,NULL);
  160.     PSsetgray(background_gray);
  161.     NXRectFill(&backgroundRect);
  162.     
  163.     if (just_erase) return self;
  164.     
  165.     // compute for drawing
  166.     
  167.     if (running)
  168.         {
  169.         left=0;right=0;
  170.         
  171.         if (input&&input_device!=NULL) 
  172.             [input_device getPeakLeft:&left right:&right];
  173.         
  174.         if ((!input)&&output_device!=NULL)
  175.             [output_device getPeakLeft:&left right:&right];
  176.             
  177.         // perform refresh computations
  178.          
  179.         if (++refresh_tally>=refreshes_per_new_peak_bubble) refresh_tally=0;
  180.         refreshes_left[refresh_tally]=left;
  181.         refreshes_right[refresh_tally]=right;
  182.         if (left>=refreshes_left[current_max_refresh_left])
  183.     
  184.     // remember, this might simply be because left stepped on the old champion!
  185.     // ...search for new champion
  186.     
  187.             {
  188.             int y;
  189.             int maxpos=0;
  190.             for (y=0;y<refreshes_per_new_peak_bubble;y++)
  191.                 if (refreshes_left[y]>refreshes_left[maxpos]) maxpos=y;
  192.             current_max_refresh_left=maxpos;
  193.             }
  194.         if (right>=refreshes_right[current_max_refresh_right])
  195.             // same as above!
  196.             // ...search for new champion
  197.             {
  198.             int y;
  199.             int maxpos=0;
  200.             for (y=0;y<refreshes_per_new_peak_bubble;y++)
  201.                 if (refreshes_right[y]>refreshes_right[maxpos]) maxpos=y;
  202.             current_max_refresh_right=maxpos;
  203.             }
  204.         
  205.         // Draw away...
  206.             
  207.         if (VOLUMEMETER_draw_wide(&valueRect))        // draw wide
  208.             {
  209.                 
  210.             if (stereo)
  211.                 {
  212.                 
  213.                 // note that right and left are flipped,
  214.                 // so that when displaying wide, left is on the top.
  215.                 
  216.                 drawRectRight=valueRect;
  217.                 drawRectRight.size.height*=1-VOLUMEMETER_RIGHT_BEGIN;
  218.                 drawRectRight.origin.y+=valueRect.size.height*
  219.                         VOLUMEMETER_RIGHT_BEGIN;
  220.                 drawRectRight.size.width*=left;
  221.             
  222.                 drawRectLeft=valueRect;
  223.                 drawRectLeft.size.height*=VOLUMEMETER_LEFT_END;
  224.                 drawRectLeft.size.width*=right;
  225.                 }
  226.             else
  227.                 {
  228.                 drawRectRight=valueRect;
  229.                 drawRectRight.size.width*=(right+left)/2.0;
  230.                 }
  231.             }
  232.         else                                        // draw tall
  233.             {
  234.             
  235.             if (stereo)
  236.                 {
  237.                 drawRectRight=valueRect;
  238.                 drawRectRight.size.width*=1-VOLUMEMETER_RIGHT_BEGIN;
  239.                 drawRectRight.origin.x+=valueRect.size.width*
  240.                         VOLUMEMETER_RIGHT_BEGIN;
  241.                 drawRectRight.size.height*=right;
  242.             
  243.                 drawRectLeft=valueRect;
  244.                 drawRectLeft.size.width*=VOLUMEMETER_LEFT_END;
  245.                 drawRectLeft.size.height*=left;
  246.                 }
  247.             else
  248.                 {
  249.                 drawRectRight=valueRect;
  250.                 drawRectRight.size.height*=(right+left)/2.0;
  251.                 }
  252.             }
  253.         if (left+right>0.0)            
  254.         
  255.         // I go through the computation because peak bubbles need it
  256.         
  257.             {
  258.             PSsetgray(value_gray);
  259.             NXRectFill(&drawRectRight);
  260.             if (stereo) NXRectFill(&drawRectLeft);
  261.             }
  262.         // Draw Peak Bubbles            
  263.  
  264.         if (peak_bubble_displayed)
  265.             {
  266.             NXRect rightRect=drawRectRight;
  267.             NXRect leftRect=drawRectLeft;
  268.             float max_left=refreshes_left[current_max_refresh_left];
  269.             float max_right=refreshes_right[current_max_refresh_right];
  270.             
  271.             if (max_left+max_right>0.0)
  272.                 {
  273.             
  274.                 if (VOLUMEMETER_draw_wide(&valueRect))        // draw wide
  275.                     {
  276.                     rightRect.size.width=0.1;            // ...makes it a line
  277.                     leftRect.size.width=0.1;
  278.                     
  279.                     if (stereo)
  280.                         {
  281.                         rightRect.origin.x=floor(drawRectRight.origin.x+
  282.                             valueRect.size.width*max_left);
  283.                         leftRect.origin.x=floor(drawRectLeft.origin.x+
  284.                             valueRect.size.width*max_right);
  285.                         }
  286.                     else
  287.                         {
  288.                         rightRect.origin.x=floor(drawRectRight.origin.x+
  289.                             valueRect.size.width*
  290.                             (max_right+max_left)/2.0);
  291.                         }
  292.                     }    
  293.                 else                                        // draw tall
  294.                     {
  295.                     rightRect.size.height=0.1;                // makes it a line
  296.                     leftRect.size.height=0.1;
  297.                     
  298.                     if (stereo)
  299.                         {
  300.                         rightRect.origin.y=floor(drawRectRight.origin.y+
  301.                             valueRect.size.height*max_right);
  302.                         leftRect.origin.y=floor(drawRectLeft.origin.y+
  303.                             valueRect.size.height*max_left);
  304.                         }
  305.                     else
  306.                         {
  307.                         rightRect.origin.y=floor(drawRectRight.origin.y+
  308.                             valueRect.size.height*
  309.                             (max_right+max_left)/2.0);
  310.                         }
  311.                     }
  312.                 PSsetgray(bubble_gray);
  313.                 NXRectFill(&rightRect);
  314.                 if (stereo) NXRectFill(&leftRect);
  315.                 }
  316.             }
  317.         }
  318.     NXPing();
  319.     if ([delegate respondsTo:@selector(meterDidUpdate:)])
  320.         [delegate meterDidUpdate:self];
  321.     // else...
  322.     return self;
  323.     }
  324.  
  325.  
  326. - setMono
  327.     {
  328.     stereo=NO;
  329.     //[self display];
  330.     return self;
  331.     }
  332.     
  333. - setStereo
  334.     {
  335.     stereo=YES;
  336.     //[self display];
  337.     return self;
  338.     }
  339.  
  340. - setBackgroundGray:(float) this_value
  341.     {
  342.     if (this_value>=0&&this_value<=1) background_gray=this_value;
  343.     [self display];
  344.     return self;
  345.     }
  346.  
  347. - setValueGray:(float) this_value
  348.     {
  349.     if (this_value>=0&&this_value<=1) value_gray=this_value;
  350.     [self display];
  351.     return self;
  352.     }
  353.  
  354. - setBubbleGray: (float) this_value
  355.     {
  356.     if (this_value>=0&&this_value<=1) bubble_gray=this_value;
  357.     [self display];
  358.     return self;
  359.     }
  360.  
  361. - (float) backgroundGray
  362.     {
  363.     return background_gray;
  364.     }
  365.  
  366. - (float) valueGray
  367.     {
  368.     return value_gray;
  369.     }
  370.  
  371. - (float) bubbleGray
  372.     {
  373.     return bubble_gray;
  374.     }
  375.  
  376. - setBezeled:(BOOL) yes_or_no
  377.     {
  378.     bezeled=yes_or_no;
  379.     [self display];
  380.     return self;
  381.     }
  382.  
  383. - setPeakBubbleDisplayed:(BOOL) yes_or_no
  384.     {
  385.     peak_bubble_displayed=yes_or_no;
  386.     [self display];
  387.     return self;
  388.     }
  389.  
  390. - setToInput
  391.     {
  392.     input=YES;
  393.         // try to allocate once more...
  394.     [self reclaim];
  395.         // ...then test
  396.     if (input_device==NULL) return NULL;
  397.     return self;
  398.     }
  399.  
  400. - setToOutput
  401.     {
  402.     input=NO;
  403.         // try to allocate once more...
  404.     [self reclaim];
  405.         // ...then test
  406.     if (output_device==NULL) return NULL;
  407.     return self;
  408.     }
  409.  
  410. - setRefresh:(float) number_seconds
  411.     {
  412.     if (number_seconds>0)
  413.         {
  414.         refresh=number_seconds;
  415.         if (teNum) 
  416.             {
  417.             DPSRemoveTimedEntry(teNum);
  418.             teNum=DPSAddTimedEntry(refresh, 
  419.                 (DPSTimedEntryProc) VOLUMEMETER_update_meter,
  420.                 (void*) self, (int) NX_RUNMODALTHRESHOLD);
  421.             }
  422.         }
  423.     return self;
  424.     }
  425.     
  426. - setRefreshesPerNewPeakBubble:(int) number_refreshes
  427.     {
  428.     if (number_refreshes<=VOLUMEMETER_MAX_REFRESHES&&number_refreshes>0)
  429.         {
  430.         int x;
  431.         refreshes_per_new_peak_bubble=number_refreshes;
  432.         for (x=0;x<number_refreshes;x++) 
  433.             {refreshes_left[x]=0.0;refreshes_right[x]=0.0;}
  434.         current_max_refresh_left=0;
  435.         current_max_refresh_right=0;
  436.         refresh_tally=0;
  437.         }
  438.     return self;
  439.     }
  440.  
  441. - reclaim
  442.     {
  443.     // try to grab devices
  444.     
  445.     if (input_device==NULL) input_device=[[NXSoundIn alloc] init];
  446.     if (output_device==NULL) output_device=[[NXSoundOut alloc] init];
  447.     
  448.     // reset devices
  449.     
  450.     [input_device setDetectPeaks:YES];
  451.     [output_device setDetectPeaks:YES];
  452.     
  453.     // don't display here!  That would create a loop.
  454.     return self;
  455.     }
  456.  
  457. - run
  458.     {
  459.     running=YES;
  460.     //printf ("Run\n");
  461.     if (!teNum) teNum=DPSAddTimedEntry(refresh, 
  462.             (DPSTimedEntryProc) VOLUMEMETER_update_meter,
  463.             (void*) self, (int) NX_RUNMODALTHRESHOLD);
  464.     [self display];
  465.     return self;
  466.     }
  467.  
  468. - stop
  469.     {
  470.     running=NO;
  471.     //printf ("Stop\n");
  472.     if (teNum) DPSRemoveTimedEntry(teNum);
  473.     teNum=0;
  474.     [self display];
  475.     return self;
  476.     }
  477.     
  478. - read:(NXTypedStream*) stream
  479.     {
  480.     [super read:stream];
  481.     NXReadTypes(stream,"cccccfff",&input,&running,&bezeled,
  482.         &peak_bubble_displayed,&stereo,
  483.         &background_gray,&value_gray,&bubble_gray);
  484.     return self;
  485.     }
  486.  
  487. - write:(NXTypedStream*) stream
  488.     {
  489.     [super write:stream];
  490.     NXWriteTypes(stream,"cccccfff",&input,&running,&bezeled,
  491.         &peak_bubble_displayed,&stereo,
  492.         &background_gray,&value_gray,&bubble_gray);
  493.     return self;
  494.     }
  495.  
  496. - free
  497.     {
  498.     if (teNum) DPSRemoveTimedEntry(teNum);
  499.     teNum=0;
  500.     if (input_device!=NULL) [input_device free];
  501.     if (output_device!=NULL) [output_device free];
  502.     return [super free];
  503.     }
  504.  
  505. - awake
  506.     {
  507.     int x;
  508.     
  509.     [super awake];
  510.     
  511.     refresh=VOLUMEMETER_TIMED_ENTRY_SPEED;
  512.     refreshes_per_new_peak_bubble=VOLUMEMETER_STD_REFRESHES;
  513.     refresh_tally=0;
  514.     for (x=0;x<VOLUMEMETER_MAX_REFRESHES;x++) 
  515.         {refreshes_left[x]=0.0;refreshes_right[x]=0.0;}
  516.     current_max_refresh_left=0;
  517.     current_max_refresh_right=0;
  518.     
  519.     if (input_device==NULL) input_device= [[NXSoundIn alloc] init];
  520.     if (output_device==NULL) output_device=[[NXSoundOut alloc] init];
  521.     [input_device setDetectPeaks:YES];
  522.     [output_device setDetectPeaks:YES];            // for symmetry;
  523.  
  524.     if (running) [self run];
  525.     return self;
  526.     }
  527.  
  528. - setMono:sender
  529.     {
  530.     return [self setMono];
  531.     }
  532.  
  533. - setStereo:sender
  534.     {
  535.     return [self setStereo];
  536.     }
  537.  
  538. - setToInput:sender
  539.     {
  540.     return [self setToInput];
  541.     }
  542.  
  543. - setToOutput:sender
  544.     {
  545.     return [self setToOutput];
  546.     }
  547.  
  548. - run:sender
  549.     {
  550.     return [self run];
  551.     }
  552.  
  553. - stop:sender
  554.     {
  555.     return [self stop];
  556.     }
  557.  
  558. - windowDidBecomeKey:sender
  559.     {
  560.     id temp=self;
  561.     if ([delegate respondsTo:@selector(windowDidBecomeKey:)])
  562.         temp=[delegate windowDidBecomeKey:sender];
  563.     if (temp!=NULL) [self reclaim];
  564.     if (temp!=NULL) [self run];
  565.     return self;
  566.     }
  567.     
  568.     
  569. - windowDidBecomeMain:sender
  570.     {
  571.     id temp=self;
  572.     if ([delegate respondsTo:@selector(windowDidBecomeMain:)])
  573.         temp=[delegate windowDidBecomeMain:sender];
  574.     if (temp!=NULL) [self reclaim];
  575.     if (temp!=NULL) [self run];
  576.     return self;
  577.     }
  578.     
  579.     
  580.  
  581. - windowDidDeminiaturize:sender
  582.     {
  583.     id temp=self;
  584.     if ([delegate respondsTo:@selector(windowDidDeminiaturize:)])
  585.         temp=[delegate windowDidDeminiaturize:sender];
  586.     if (temp!=NULL) [self reclaim];
  587.     if (temp!=NULL) [self run];
  588.     return self;
  589.     }
  590.     
  591.     
  592.  
  593. - windowDidMiniaturize:sender
  594.     {
  595.     id temp=self;
  596.     if ([delegate respondsTo:@selector(windowDidMiniaturize:)])
  597.         temp=[delegate windowDidMiniaturize:sender];
  598.     if (temp!=NULL) [self stop];
  599.     return self;
  600.     }
  601.     
  602.     
  603. - windowWillClose:sender
  604.     {
  605.     id temp=self;
  606.     if ([delegate respondsTo:@selector(windowWillClose:)])
  607.         temp=[delegate windowWillClose:sender];
  608.     if (temp!=NULL) [self stop];
  609.     return self;
  610.     }
  611.     
  612. - setSound:this_sound
  613.     {
  614.     sound=this_sound;
  615.     [self display];
  616.     return self;
  617.     }
  618.  
  619. - sound
  620.     {
  621.     return sound;
  622.     }
  623.     
  624. - setDelegate:this_delegate
  625.     {
  626.     delegate=this_delegate;
  627.     return self;
  628.     }
  629.     
  630. - delegate
  631.     {
  632.     return delegate;
  633.     }
  634.     
  635.  
  636. - (BOOL) isBezeled:sender
  637.     {
  638.     return bezeled;
  639.     }
  640.     
  641. - (BOOL) peakBubbleDisplayed:sender
  642.     {
  643.     return peak_bubble_displayed;
  644.     }
  645.     
  646.  
  647. - (BOOL) isInput:sender
  648.     {
  649.     return input;
  650.     }
  651.     
  652.  
  653. - (BOOL) isStereo:sender
  654.     {
  655.     return stereo;
  656.     }
  657.     
  658.  
  659. - (float) refresh:sender
  660.     {
  661.     return refresh;
  662.     }
  663.     
  664.  
  665. - (int) updatesPerPeakBubble:sender
  666.     {
  667.     return refreshes_per_new_peak_bubble;
  668.     }
  669.     
  670.     
  671. // The following are delegate methods, just listed here to stop warnings
  672. - meterWillUpdateOnOwn:sender {return self;}
  673. - meterWillUpdate:sender {return self;}    
  674. - meterDidUpdate:sender    {return self;}    
  675.     
  676.     
  677. @end
  678.