home *** CD-ROM | disk | FTP | other *** search
-
- #import "MiscVolumeMeter.h"
- #import <stdio.h>
-
- @implementation MiscVolumeMeter
-
- // slave method to the below timed entry function
-
- - _update
- {
- if ([delegate respondsTo:@selector(meterWillUpdateOnOwn:)])
- [delegate meterWillUpdateOnOwn:self];
- return [self display];
- }
-
-
- // timed entry procedure for periodically updating
-
- DPSTimedEntryProc VOLUMEMETER_update_meter
- (DPSTimedEntry teNum,double now, void* the_meter)
- {
- MiscVolumeMeter* temp_meter=(MiscVolumeMeter*) the_meter;
- //printf ("Display!\n");
- [temp_meter _update];
- return (void*) NULL;
- }
-
-
- // convenience functions
-
- BOOL VOLUMEMETER_draw_wide(const NXRect* aRect)
- {
- return (BOOL) (aRect->size.width>=aRect->size.height);
- }
-
- BOOL VOLUMEMETER_can_draw(const NXRect* aRect)
- {
- return (BOOL) (aRect->size.width>VOLUMEMETER_VALUE_INSET*2
- &&aRect->size.height>VOLUMEMETER_VALUE_INSET*2);
- }
-
-
-
- // methods
-
- - initFrame:(const NXRect*) frameRect
- {
- int x;
-
- [super initFrame:frameRect];
-
- delegate=NULL;
- input=NO;
- running=NO;
- bezeled=YES;
- peak_bubble_displayed=YES;
- stereo=YES;
- background_gray=NX_DKGRAY;
- value_gray=NX_LTGRAY;
- bubble_gray=NX_WHITE;
- refresh=VOLUMEMETER_TIMED_ENTRY_SPEED;
- refreshes_per_new_peak_bubble=VOLUMEMETER_STD_REFRESHES;
- refresh_tally=0;
- for (x=0;x<VOLUMEMETER_MAX_REFRESHES;x++)
- {refreshes_left[x]=0.0;refreshes_right[x]=0.0;}
- current_max_refresh_left=0;
- current_max_refresh_right=0;
-
- if (input_device==NULL) input_device= [[NXSoundIn alloc] init];
- if (output_device==NULL) output_device=[[NXSoundOut alloc] init];
- [input_device setDetectPeaks:YES];
- [output_device setDetectPeaks:YES];
- teNum=0;
-
- return self;
- }
-
-
-
- - drawSelf:(const NXRect*) rects:(int) rectCount
- {
- NXRect drawRectLeft,drawRectRight;
- NXRect backgroundRect=bounds;
- NXRect valueRect=bounds;
- float left,right;
- int just_erase=0;
-
- //if (![window isVisible]) return NULL; // no window to draw in.
- // the above has been turned off because when loading Resound,
- // the sound meter wouldn't display until a sound was being played
- // or recorded!
-
- if ([delegate respondsTo:@selector(meterWillUpdate:)])
- [delegate meterWillUpdate:self];
-
- // first to check to see if the sound lock is current
- //printf ("Meter\n");
- if (sound!=NULL)
- {
- int status=NX_SoundStopped;
- id actual_sound=NULL; // quiets compiler complaints
-
- if ([sound isKindOf:[Sound class]])
- {actual_sound=sound;}
- else if ([sound isKindOf:[SoundView class]])
- {actual_sound=[sound soundBeingProcessed];}
- status=[actual_sound status];
- if (status==NX_SoundStopped||
- status==NX_SoundInitialized||
- status==NX_SoundFreed)
- {just_erase=1;}
-
- // Then modify the meter to match the sound
-
- else if (status==NX_SoundRecordingPaused||
- status==NX_SoundRecording||
- status==NX_SoundRecordingPending)
- {[self setToInput];}
-
- else if (status==NX_SoundPlayingPaused||
- status==NX_SoundPlaying||
- status==NX_SoundPlayingPending)
- {[self setToOutput];}
-
- if ([actual_sound channelCount]>1)
- {[self setStereo];}
- else {[self setMono];}
- }
-
- // then check for bezeled stuff
-
-
- if (bezeled)
- {
- backgroundRect.origin.x +=VOLUMEMETER_BACKGROUND_INSET;
- backgroundRect.size.width -=VOLUMEMETER_BACKGROUND_INSET*2;
- backgroundRect.origin.y +=VOLUMEMETER_BACKGROUND_INSET;
- backgroundRect.size.height -=VOLUMEMETER_BACKGROUND_INSET*2;
-
- valueRect.origin.x +=VOLUMEMETER_VALUE_INSET;
- valueRect.size.width -=VOLUMEMETER_VALUE_INSET*2;
- valueRect.origin.y +=VOLUMEMETER_VALUE_INSET;
- valueRect.size.height -=VOLUMEMETER_VALUE_INSET*2;
- }
- else
- {
- valueRect.origin.x +=
- VOLUMEMETER_VALUE_INSET-VOLUMEMETER_BACKGROUND_INSET;
- valueRect.size.width -=
- VOLUMEMETER_VALUE_INSET*2-VOLUMEMETER_BACKGROUND_INSET*2;
- valueRect.origin.y +=
- VOLUMEMETER_VALUE_INSET-VOLUMEMETER_BACKGROUND_INSET;
- valueRect.size.height -=
- VOLUMEMETER_VALUE_INSET*2-VOLUMEMETER_BACKGROUND_INSET*2;
- }
-
- if (!VOLUMEMETER_can_draw(&bounds)) return self; // can't draw
-
- if (bezeled) NXDrawGrayBezel(&bounds,NULL);
- PSsetgray(background_gray);
- NXRectFill(&backgroundRect);
-
- if (just_erase) return self;
-
- // compute for drawing
-
- if (running)
- {
- left=0;right=0;
-
- if (input&&input_device!=NULL)
- [input_device getPeakLeft:&left right:&right];
-
- if ((!input)&&output_device!=NULL)
- [output_device getPeakLeft:&left right:&right];
-
- // perform refresh computations
-
- if (++refresh_tally>=refreshes_per_new_peak_bubble) refresh_tally=0;
- refreshes_left[refresh_tally]=left;
- refreshes_right[refresh_tally]=right;
- if (left>=refreshes_left[current_max_refresh_left])
-
- // remember, this might simply be because left stepped on the old champion!
- // ...search for new champion
-
- {
- int y;
- int maxpos=0;
- for (y=0;y<refreshes_per_new_peak_bubble;y++)
- if (refreshes_left[y]>refreshes_left[maxpos]) maxpos=y;
- current_max_refresh_left=maxpos;
- }
- if (right>=refreshes_right[current_max_refresh_right])
- // same as above!
- // ...search for new champion
- {
- int y;
- int maxpos=0;
- for (y=0;y<refreshes_per_new_peak_bubble;y++)
- if (refreshes_right[y]>refreshes_right[maxpos]) maxpos=y;
- current_max_refresh_right=maxpos;
- }
-
- // Draw away...
-
- if (VOLUMEMETER_draw_wide(&valueRect)) // draw wide
- {
-
- if (stereo)
- {
-
- // note that right and left are flipped,
- // so that when displaying wide, left is on the top.
-
- drawRectRight=valueRect;
- drawRectRight.size.height*=1-VOLUMEMETER_RIGHT_BEGIN;
- drawRectRight.origin.y+=valueRect.size.height*
- VOLUMEMETER_RIGHT_BEGIN;
- drawRectRight.size.width*=left;
-
- drawRectLeft=valueRect;
- drawRectLeft.size.height*=VOLUMEMETER_LEFT_END;
- drawRectLeft.size.width*=right;
- }
- else
- {
- drawRectRight=valueRect;
- drawRectRight.size.width*=(right+left)/2.0;
- }
- }
- else // draw tall
- {
-
- if (stereo)
- {
- drawRectRight=valueRect;
- drawRectRight.size.width*=1-VOLUMEMETER_RIGHT_BEGIN;
- drawRectRight.origin.x+=valueRect.size.width*
- VOLUMEMETER_RIGHT_BEGIN;
- drawRectRight.size.height*=right;
-
- drawRectLeft=valueRect;
- drawRectLeft.size.width*=VOLUMEMETER_LEFT_END;
- drawRectLeft.size.height*=left;
- }
- else
- {
- drawRectRight=valueRect;
- drawRectRight.size.height*=(right+left)/2.0;
- }
- }
- if (left+right>0.0)
-
- // I go through the computation because peak bubbles need it
-
- {
- PSsetgray(value_gray);
- NXRectFill(&drawRectRight);
- if (stereo) NXRectFill(&drawRectLeft);
- }
- // Draw Peak Bubbles
-
- if (peak_bubble_displayed)
- {
- NXRect rightRect=drawRectRight;
- NXRect leftRect=drawRectLeft;
- float max_left=refreshes_left[current_max_refresh_left];
- float max_right=refreshes_right[current_max_refresh_right];
-
- if (max_left+max_right>0.0)
- {
-
- if (VOLUMEMETER_draw_wide(&valueRect)) // draw wide
- {
- rightRect.size.width=0.1; // ...makes it a line
- leftRect.size.width=0.1;
-
- if (stereo)
- {
- rightRect.origin.x=floor(drawRectRight.origin.x+
- valueRect.size.width*max_left);
- leftRect.origin.x=floor(drawRectLeft.origin.x+
- valueRect.size.width*max_right);
- }
- else
- {
- rightRect.origin.x=floor(drawRectRight.origin.x+
- valueRect.size.width*
- (max_right+max_left)/2.0);
- }
- }
- else // draw tall
- {
- rightRect.size.height=0.1; // makes it a line
- leftRect.size.height=0.1;
-
- if (stereo)
- {
- rightRect.origin.y=floor(drawRectRight.origin.y+
- valueRect.size.height*max_right);
- leftRect.origin.y=floor(drawRectLeft.origin.y+
- valueRect.size.height*max_left);
- }
- else
- {
- rightRect.origin.y=floor(drawRectRight.origin.y+
- valueRect.size.height*
- (max_right+max_left)/2.0);
- }
- }
- PSsetgray(bubble_gray);
- NXRectFill(&rightRect);
- if (stereo) NXRectFill(&leftRect);
- }
- }
- }
- NXPing();
- if ([delegate respondsTo:@selector(meterDidUpdate:)])
- [delegate meterDidUpdate:self];
- // else...
- return self;
- }
-
-
- - setMono
- {
- stereo=NO;
- //[self display];
- return self;
- }
-
- - setStereo
- {
- stereo=YES;
- //[self display];
- return self;
- }
-
- - setBackgroundGray:(float) this_value
- {
- if (this_value>=0&&this_value<=1) background_gray=this_value;
- [self display];
- return self;
- }
-
- - setValueGray:(float) this_value
- {
- if (this_value>=0&&this_value<=1) value_gray=this_value;
- [self display];
- return self;
- }
-
- - setBubbleGray: (float) this_value
- {
- if (this_value>=0&&this_value<=1) bubble_gray=this_value;
- [self display];
- return self;
- }
-
- - (float) backgroundGray
- {
- return background_gray;
- }
-
- - (float) valueGray
- {
- return value_gray;
- }
-
- - (float) bubbleGray
- {
- return bubble_gray;
- }
-
- - setBezeled:(BOOL) yes_or_no
- {
- bezeled=yes_or_no;
- [self display];
- return self;
- }
-
- - setPeakBubbleDisplayed:(BOOL) yes_or_no
- {
- peak_bubble_displayed=yes_or_no;
- [self display];
- return self;
- }
-
- - setToInput
- {
- input=YES;
- // try to allocate once more...
- [self reclaim];
- // ...then test
- if (input_device==NULL) return NULL;
- return self;
- }
-
- - setToOutput
- {
- input=NO;
- // try to allocate once more...
- [self reclaim];
- // ...then test
- if (output_device==NULL) return NULL;
- return self;
- }
-
- - setRefresh:(float) number_seconds
- {
- if (number_seconds>0)
- {
- refresh=number_seconds;
- if (teNum)
- {
- DPSRemoveTimedEntry(teNum);
- teNum=DPSAddTimedEntry(refresh,
- (DPSTimedEntryProc) VOLUMEMETER_update_meter,
- (void*) self, (int) NX_RUNMODALTHRESHOLD);
- }
- }
- return self;
- }
-
- - setRefreshesPerNewPeakBubble:(int) number_refreshes
- {
- if (number_refreshes<=VOLUMEMETER_MAX_REFRESHES&&number_refreshes>0)
- {
- int x;
- refreshes_per_new_peak_bubble=number_refreshes;
- for (x=0;x<number_refreshes;x++)
- {refreshes_left[x]=0.0;refreshes_right[x]=0.0;}
- current_max_refresh_left=0;
- current_max_refresh_right=0;
- refresh_tally=0;
- }
- return self;
- }
-
- - reclaim
- {
- // try to grab devices
-
- if (input_device==NULL) input_device=[[NXSoundIn alloc] init];
- if (output_device==NULL) output_device=[[NXSoundOut alloc] init];
-
- // reset devices
-
- [input_device setDetectPeaks:YES];
- [output_device setDetectPeaks:YES];
-
- // don't display here! That would create a loop.
- return self;
- }
-
- - run
- {
- running=YES;
- //printf ("Run\n");
- if (!teNum) teNum=DPSAddTimedEntry(refresh,
- (DPSTimedEntryProc) VOLUMEMETER_update_meter,
- (void*) self, (int) NX_RUNMODALTHRESHOLD);
- [self display];
- return self;
- }
-
- - stop
- {
- running=NO;
- //printf ("Stop\n");
- if (teNum) DPSRemoveTimedEntry(teNum);
- teNum=0;
- [self display];
- return self;
- }
-
- - read:(NXTypedStream*) stream
- {
- [super read:stream];
- NXReadTypes(stream,"cccccfff",&input,&running,&bezeled,
- &peak_bubble_displayed,&stereo,
- &background_gray,&value_gray,&bubble_gray);
- return self;
- }
-
- - write:(NXTypedStream*) stream
- {
- [super write:stream];
- NXWriteTypes(stream,"cccccfff",&input,&running,&bezeled,
- &peak_bubble_displayed,&stereo,
- &background_gray,&value_gray,&bubble_gray);
- return self;
- }
-
- - free
- {
- if (teNum) DPSRemoveTimedEntry(teNum);
- teNum=0;
- if (input_device!=NULL) [input_device free];
- if (output_device!=NULL) [output_device free];
- return [super free];
- }
-
- - awake
- {
- int x;
-
- [super awake];
-
- refresh=VOLUMEMETER_TIMED_ENTRY_SPEED;
- refreshes_per_new_peak_bubble=VOLUMEMETER_STD_REFRESHES;
- refresh_tally=0;
- for (x=0;x<VOLUMEMETER_MAX_REFRESHES;x++)
- {refreshes_left[x]=0.0;refreshes_right[x]=0.0;}
- current_max_refresh_left=0;
- current_max_refresh_right=0;
-
- if (input_device==NULL) input_device= [[NXSoundIn alloc] init];
- if (output_device==NULL) output_device=[[NXSoundOut alloc] init];
- [input_device setDetectPeaks:YES];
- [output_device setDetectPeaks:YES]; // for symmetry;
-
- if (running) [self run];
- return self;
- }
-
- - setMono:sender
- {
- return [self setMono];
- }
-
- - setStereo:sender
- {
- return [self setStereo];
- }
-
- - setToInput:sender
- {
- return [self setToInput];
- }
-
- - setToOutput:sender
- {
- return [self setToOutput];
- }
-
- - run:sender
- {
- return [self run];
- }
-
- - stop:sender
- {
- return [self stop];
- }
-
- - windowDidBecomeKey:sender
- {
- id temp=self;
- if ([delegate respondsTo:@selector(windowDidBecomeKey:)])
- temp=[delegate windowDidBecomeKey:sender];
- if (temp!=NULL) [self reclaim];
- if (temp!=NULL) [self run];
- return self;
- }
-
-
- - windowDidBecomeMain:sender
- {
- id temp=self;
- if ([delegate respondsTo:@selector(windowDidBecomeMain:)])
- temp=[delegate windowDidBecomeMain:sender];
- if (temp!=NULL) [self reclaim];
- if (temp!=NULL) [self run];
- return self;
- }
-
-
-
- - windowDidDeminiaturize:sender
- {
- id temp=self;
- if ([delegate respondsTo:@selector(windowDidDeminiaturize:)])
- temp=[delegate windowDidDeminiaturize:sender];
- if (temp!=NULL) [self reclaim];
- if (temp!=NULL) [self run];
- return self;
- }
-
-
-
- - windowDidMiniaturize:sender
- {
- id temp=self;
- if ([delegate respondsTo:@selector(windowDidMiniaturize:)])
- temp=[delegate windowDidMiniaturize:sender];
- if (temp!=NULL) [self stop];
- return self;
- }
-
-
- - windowWillClose:sender
- {
- id temp=self;
- if ([delegate respondsTo:@selector(windowWillClose:)])
- temp=[delegate windowWillClose:sender];
- if (temp!=NULL) [self stop];
- return self;
- }
-
- - setSound:this_sound
- {
- sound=this_sound;
- [self display];
- return self;
- }
-
- - sound
- {
- return sound;
- }
-
- - setDelegate:this_delegate
- {
- delegate=this_delegate;
- return self;
- }
-
- - delegate
- {
- return delegate;
- }
-
-
- - (BOOL) isBezeled:sender
- {
- return bezeled;
- }
-
- - (BOOL) peakBubbleDisplayed:sender
- {
- return peak_bubble_displayed;
- }
-
-
- - (BOOL) isInput:sender
- {
- return input;
- }
-
-
- - (BOOL) isStereo:sender
- {
- return stereo;
- }
-
-
- - (float) refresh:sender
- {
- return refresh;
- }
-
-
- - (int) updatesPerPeakBubble:sender
- {
- return refreshes_per_new_peak_bubble;
- }
-
-
- // The following are delegate methods, just listed here to stop warnings
- - meterWillUpdateOnOwn:sender {return self;}
- - meterWillUpdate:sender {return self;}
- - meterDidUpdate:sender {return self;}
-
-
- @end
-