This is MLMKVMaster.m in view mode; [Download] [Up]
// Copyright (94) by melonSoft Ralf Suckow Berlin, All Rights Reserved // Note: sometimes we use the Class * type instead of id since // the appkit includes the soundkit, which has different definitions // for the activate and info methods. #import "MLMKVMaster.h" #import "MLParameters.h" #import <musickit/musickit.h> #import <dsp/dsp.h> @implementation MLMKVMaster - appDidInit:sender { static char name[80]; sprintf (name, VOICE_PRODUCER_NAME, "score-tmpl"); [[NXConnection registerRoot:self withName:name] runFromAppKit]; // initialize self [Orchestra setSamplingRate:44100.0]; [Conductor setClocked:NO]; [Conductor setThreadPriority:1.0]; [PartPerformer setFastActivation:YES]; orchestra = [Orchestra new]; if (![orchestra open]) { NXRunAlertPanel ("MusicKit Voice Interpreter", "Can't open Digital Signal Processor. Do you have one? Maybe another application is using it. Also, the MusicKit needs to be installed on your computer!", NULL, NULL, NULL); } [orchestra close]; return self; } - showError:(const char *)text with:(const char *)parameter { NXRunAlertPanel ("MusicKit Voice Interpreter", text, NULL, NULL, NULL, parameter); return self; } - (NXStream *)expandScore:(NXStream *)inputStream fromParameters:params { NXStream * outputStream; char parameterName[1024]; int c; int count; const char * value; if (!inputStream) return NULL; // replacing all patterns like $parameter$ by their value from params if (!(outputStream = NXOpenMemory (NULL, 0, NX_READWRITE))) return NULL; while ((c = NXGetc (inputStream)) != EOF) if (c != '$') NXPutc (outputStream, c); else { count = 0; while ((c = NXGetc (inputStream)) != EOF && count < 1023) if (c != '$') parameterName[count++] = c; else break; if (!count) NXPutc (outputStream, '$'); // two $$s are a single $ else if (count == 1023) { [self showError:"Parameter name too long" with:""]; NXClose (outputStream); return NULL; } else { parameterName[count] = '\0'; value = [params valueFor:NXUniqueString(parameterName)]; if (!value) { [self showError:"Parameter `%s' not found" with:parameterName]; NXClose (outputStream); return NULL; } NXPrintf (outputStream, "%s", value); } } NXSeek (outputStream, 0, NX_FROMSTART); return outputStream; } - (BOOL)makeFile:(const char *)outputFile fromVoice:(const char *)inputFile parameters:params { NXStream * scoreTemplateStream; NXStream * expandedScoreStream; BOOL ok; id score; ok = YES; NX_DURING scoreTemplateStream = NXMapFile (inputFile,NX_READONLY); NX_HANDLER [self showError:"I/O error -- Can't open file `%s'" with:inputFile]; ok = NO; NX_ENDHANDLER if (ok) { expandedScoreStream = [self expandScore:scoreTemplateStream fromParameters:params]; NXClose (scoreTemplateStream); if (expandedScoreStream) { score = [[Score alloc] init]; if (![score readScorefileStream:expandedScoreStream]) { [self showError:"bad syntax of scorefile `%s'" with:inputFile]; ok = NO; } else ok = [self makeFile:outputFile fromScore:score]; [score free]; NXClose (expandedScoreStream); } else ok = NO; } return ok; } - (BOOL)makeFile:(const char *)outputFile fromScore:(Score *)score { ScorePerformer * scorePerformer; id partPerformers; id instruments; BOOL ok; int i; id partPerformer; Part * part; id partInfo; char * className; id synthPatchClass; id instrument; scorePerformer = [[ScorePerformer alloc] init]; [scorePerformer setScore:score]; [scorePerformer activate]; if ([[score info] isParPresent:MK_tempo]) [[Conductor defaultConductor] setTempo:[[score info] parAsDouble:MK_tempo]]; partPerformers = [scorePerformer partPerformers]; instruments = [[List alloc] init]; ok = YES; for (i = 0; partPerformer = [partPerformers objectAt:i]; i++) { part = [partPerformer part]; if (!(partInfo = [part info])) { [self showError: "missing info for part `%s'" with:MKGetObjectName(part)]; ok = NO; break; } if (![partInfo isParPresent:MK_synthPatch]) { [self showError: "Part `%s' without synthPatch info" with:MKGetObjectName(part)]; ok = NO; break; } className = [partInfo parAsStringNoCopy:MK_synthPatch]; if (!*className || !(synthPatchClass = [SynthPatch findSynthPatchClass:className])) { [self showError: "SynthPatch class `%s' not found" with:className]; ok = NO; break; } instrument = [[SynthInstrument alloc] init]; [instruments addObject:instrument]; [[partPerformer noteSender] connect:[instrument noteReceiver]]; [instrument setSynthPatchClass:synthPatchClass]; if ([partInfo isParPresent:MK_synthPatchCount]) [instrument setSynthPatchCount:[partInfo parAsInt:MK_synthPatchCount] patchTemplate:[synthPatchClass patchTemplateFor:partInfo]]; } if (ok) { [orchestra setOutputSoundfile:(char *)outputFile]; [orchestra run]; [Conductor startPerformance]; [orchestra close]; } [scorePerformer free]; [[instruments freeObjects] free]; return ok; } // <MLVoiceProduction> protocol - (oneway void)voice:(const char *)documentFile makeFile:(const char *)outputFile from:(const char *)parameters forClient:(id <MLProductionClient>)sender request:(int)number; { BOOL ok; id params; BOOL flag; params = [[MLParameters alloc] init]; if (![params readFromMathString:parameters syntaxOK:&flag]) ok = NO; else ok = [self makeFile:outputFile fromVoice:documentFile parameters:params]; [sender server:self didRequest:number success:(int)ok]; [params free]; // trying to free the strings -- does this always work ? if (documentFile) free ((char *)documentFile); if (outputFile) free ((char *)outputFile); if (parameters) free ((char *)parameters); } - (BOOL)appAcceptsAnotherFile:sender { return YES; } - (int)app:sender openFile:(const char *)path type:(const char *)type { // It is a better idea to forward it to Edit even if somebody is // using emacs or any other editor [self perform:@selector(doOpen:) with:(id)NXUniqueString (path) afterDelay:0 cancelPrevious:NO]; return YES; } - doOpen:path { [[Application workspace] openFile:(const char *)path withApplication:"Edit"]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.