This is TunerApp.m in view mode; [Download] [Up]
/* TunerApp.m -- copyright 1992, 1993, 1994 by C.D.Lane */ #import "TunerApp.h" #import "DefaultsTable.h" #import "PopUpListPatch.h" #import "Frequency.h" #import "ZeroFrequency.h" #import "FFTFrequency.h" #define VERSION __DATE__ #define HELPFILE "Tuner" #define DEFAULTSFILE "Defaults" #define freq(k) MKKeyNumToFreq(k) #define keyNum(f) MKFreqToKeyNum(f, NULL, 0.0) #define TONES (12) #define MSECPERSEC (1000) @implementation TunerApp : Application + new { char pathnamebuf[MAXPATHLEN]; self = [super new]; bundle = [NXBundle bundleForClass:[self class]]; if ([bundle getPath:pathnamebuf forResource:DEFAULTSFILE ofType:"strings"]) [(defaults = [[DefaultsTable alloc] initFromFile:pathnamebuf]) registerDefaults:[self appName]]; return self; } - appDidInit:sender { [[[[soundView setAutoscale:YES] setDisplayMode:SK_DISPLAY_WAVE] setAutodisplay:YES] setSound:sound]; key = lastKey = c00k; [methods addObject:[[ZeroFrequency alloc] init]]; [methods addObject:[[FFTFrequency alloc] init]]; [self loadDefaults:sender]; [sound perform:@selector(record:) with:sender afterDelay:0 cancelPrevious:YES]; return self; } - appWillTerminate:sender { return [self saveDefaults:sender]; } - willRecord:sender { [soundMeter run:sender]; [sound perform:@selector(stop:) with:sender afterDelay:([timeSlider floatValue] * MSECPERSEC) cancelPrevious:YES]; return self; } - didRecord:sender { int status = SND_ERR_NONE; id list = methodPopUpList; amplitude = [[soundMeter stop:sender] peakValue]; frequency = FREQUENCY_UNSTABLE; method = [methods objectAt:[list indexOfItem:[list selectedItem]]]; if((status = [sample copySound:sound]) == SND_ERR_NONE) { if((status = [sound deleteSamples]) == SND_ERR_NONE) { if(amplitude >= [squelchSlider floatValue]) { if((status = [sample convertToFormat:SND_FORMAT_LINEAR_16]) == SND_ERR_NONE) frequency = [method computeFrequency:sample]; #ifdef DEBUG else (void) fprintf(stderr, "convertToFormat: %s\n", SNDSoundError(status)); #endif } else [[[self clearNoteName] clearCentError] clearNoteGlyph]; } #ifdef DEBUG else (void) fprintf(stderr, "deleteSamples: %s\n", SNDSoundError(status)); #endif } #ifdef DEBUG else (void) fprintf(stderr, "copySound: %s\n", SNDSoundError(status));; #endif if(frequency == FREQUENCY_ERROR) [self switchMethod:"Switching methods, selected method not available!"]; else if(frequency != FREQUENCY_UNSTABLE) { frequency *= [adjustmentSlider floatValue]; #ifdef DEBUG (void) fprintf(stderr, "amplitude = %f\nfrequency = %f\n\n", amplitude, frequency); #endif if((key = keyNum(frequency)) % TONES == lastKey) [[[self showNoteName] showCentError] showNoteGlyph]; else [[self clearNoteName] clearCentError]; NXPing(); lastKey = key % TONES; } [sound perform:@selector(record:) with:sender afterDelay:0 cancelPrevious:YES]; return self; } - openHelpPanel:sender { NXStream *stream; static BOOL flag = NO; char pathnamebuf[MAXPATHLEN]; if(!flag) { if ([bundle getPath:pathnamebuf forResource:HELPFILE ofType:"rtf"]) { if((stream = NXMapFile(pathnamebuf, NX_READONLY)) != NULL) { [helpScrollView readRichText:stream]; NXCloseMemory(stream, NX_FREEBUFFER); flag = YES; } else return nil; } else return nil; } [[helpScrollView window] makeKeyAndOrderFront:sender]; return self; } - showNoteName { id control, list = [buttonMatrix cellList]; unsigned int i, size, state, pitch = ((key + [transpositionField intValue]) % TONES); for(i = 0, size = [list count]; i < size; i++) { state = (pitch == [(control = [list objectAt:i]) tag]); if([control state] != state) [[[control setEnabled:YES] setState:state] setEnabled:NO]; } return self; } - clearNoteName { unsigned int i, size; id control, list = [buttonMatrix cellList]; for(i = 0, size = [list count]; i < size; i++) { if([(control = [list objectAt:i]) state]) [[[control setEnabled:YES] setState:NO] setEnabled:NO]; } return self; } - showCentError { double zero, minimum, maximum, correct, calibration = [calibrationField floatValue] / freq(a4k); double error, tolerance = [toleranceSlider floatValue] + [method toleranceAtFrequency:frequency]; correct = freq(key) * calibration; minimum = freq(key - 1) * calibration; maximum = freq(key + 1) * calibration; [[[centSlider setMinValue:minimum] setMaxValue:maximum] setFloatValue:frequency]; [centSlider setEnabled:YES]; zero = (((error = frequency - correct) > 0.0) ? maximum - correct : correct - minimum) * tolerance; [flat setState:(error <= zero)]; [sharp setState:(error >= -zero)]; [attune setState:([flat state] && [sharp state])]; return self; } - clearCentError { [[[[centSlider setMinValue:freq(af4k)] setMaxValue:freq(as4k)] setFloatValue:freq(a4k)] setEnabled:NO]; [flat setState:NO]; [sharp setState:NO]; [attune setState:NO]; return self; } #import "GlyphTable.h" - showNoteGlyph { BOOL flag; id cell, image; struct entry *entry; unsigned int i, j, count = [staffMatrix cellCount]; MKKeyNum index = key + [transpositionField intValue]; if(index < START || index > END) return self; entry = &entries[i = (unsigned int) (END - index)]; if(entry->clef != NULL && (image = [NXImage findImageNamed:entry->clef]) != nil && [staffButton image] != image) { [staffButton setImage:image]; } for(j = 0, flag = NO; j < count; j++) { if(flag || (flag = (entry->notes)[j] == NULL)) image = [NXImage findImageNamed:STAFF]; else if((image = [NXImage findImageNamed:(entry->notes)[j]]) == nil) continue; if([(cell = [staffMatrix cellAt:0 :j]) image] != image) [cell setImage:image]; } return self; } - clearNoteGlyph { id image = [NXImage findImageNamed:STAFF]; [[staffMatrix cellList] makeObjectsPerform:@selector(setImage:) with:image]; return self; } - switchMethod:(const char *) reason { const char *title = "Zero"; // should be [[methods itemAt:0] ...] (void) NXRunAlertPanel([self appName], reason, NULL, NULL, NULL); [methodButton setTitle:title]; [methodPopUpList selectItem:title]; return nil; } - setDefault:sender { [sender setTag:YES]; return self; } - setCalibration:sender { [calibrationField setIntValue:[[sender selectedCell] tag]]; return [self setDefault:sender]; } - setTransposition:sender { [transpositionField setIntValue:[[sender selectedCell] tag]]; return [self setDefault:sender]; } - loadDefaults:sender; { const char *string = getStringDefault("Method"); [[squelchSlider setTag:NO] setFloatValue:getFloatDefault("Squelch")]; [[timeSlider setTag:NO] setFloatValue:getFloatDefault("SampleTime")]; [[toleranceSlider setTag:NO] setFloatValue:getFloatDefault("Tolerance")]; [[adjustmentSlider setTag:NO] setFloatValue:getFloatDefault("Adjustment")]; [calibrationField setIntValue:getIntDefault("Calibration")]; [[calibrationMatrix setTag:NO] selectCellWithTag:[calibrationField intValue]]; [transpositionField setIntValue:getIntDefault("Transposition")]; [[transpositionMatrix setTag:NO] selectCellWithTag:[transpositionField intValue]]; if ([methodPopUpList indexOfItem:string] != -1) { [methodButton setTitle:string]; [methodPopUpList selectItem:string]; } [methodMatrix setTag:NO]; return self; } - saveDefaults:sender { if([squelchSlider tag]) (void) writeDefault("Squelch", [squelchSlider stringValue]); if([timeSlider tag]) (void) writeDefault("SampleTime", [timeSlider stringValue]); if([toleranceSlider tag]) (void) writeDefault("Tolerance", [toleranceSlider stringValue]); if([adjustmentSlider tag]) (void) writeDefault("Adjustment", [adjustmentSlider stringValue]); if([calibrationMatrix tag]) (void) writeDefault("Calibration", [calibrationField stringValue]); if([transpositionMatrix tag]) (void) writeDefault("Transposition", [transpositionField stringValue]); if([methodMatrix tag]) (void) writeDefault("Method", [[methodMatrix selectedCell] title]); return self; } - resetDefaults:sender { [defaults updateDefaults]; return [self loadDefaults:sender]; } - setMethodPopUpList:anObject { [[(methodPopUpList = anObject) setTarget:self] setAction:@selector(setDefault:)]; methodMatrix = [methodPopUpList itemList]; return self; } - setVersion:anObject { [(version = anObject) setStringValue:VERSION]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.