This is MiscVolumeMeter.m in view mode; [Download] [Up]
/* MiscVolumeMeter Version 1.2 Copyright (c) 1995 by Sean Luke Donated to the MiscKit Permission to use, copy, modify, and distribute this material for any purpose and without fee, under the restrictions as noted in the MiscKit copyright notice, is hereby granted, provided that the MiscKit copyright notice and this permission notice appear in all source copies, and that the author's name shall not be used in advertising or publicity pertaining to this material without the specific, prior written permission of the author. SEAN O. LUKE MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. */ #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]; if (left>1) left=1; if (right>1) right=1; // occasionally a NeXTSTEP bug returns values larger than 1! // 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) DPSRemoveTimedEntry(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);*/ // Commented out to provide new read format: NXReadTypes(stream,"ccccffffi",&input,&bezeled, &peak_bubble_displayed,&stereo, &background_gray,&value_gray,&bubble_gray,&refresh, &refreshes_per_new_peak_bubble); return self; } - write:(NXTypedStream*) stream { [super write:stream]; /*NXWriteTypes(stream,"cccccfff",&input,&running,&bezeled, &peak_bubble_displayed,&stereo, &background_gray,&value_gray,&bubble_gray);*/ // Commented out to provide new write format: NXWriteTypes(stream,"ccccffffi",&input,&bezeled, &peak_bubble_displayed,&stereo, &background_gray,&value_gray,&bubble_gray,&refresh, &refreshes_per_new_peak_bubble); 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) refreshesPerPeakBubble:sender { return refreshes_per_new_peak_bubble; } // The following are delegate methods, just listed here to stop warnings - meterWillUpdateOnOwn:sender {return NULL;} - meterWillUpdate:sender {return NULL;} - meterDidUpdate:sender {return NULL;} - (const char*) getInspectorClassName { return "MiscVolumeMeterInspector"; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.