This is mk2stella.m in view mode; [Download] [Up]
/* * mk2stella reads a Music Kit scorefile and writes a Stella archive file, * which is actually just a lisp program. mk2stella is adapted from the * scorefile-to-lisp program written by David Jaffe at CCRMA. compile by: * cc -DNeXT_3 -g -c mk2stella.m -o mk2stella.o * cc -o mk2stella mk2stella.o -lmusickit -lNeXT_s -lsys_s */ #ifndef NeXT_2 #ifndef NeXT_3 #error "missing -D switches: NeXT_2 or NeXT_3" #endif #endif #ifdef NeXT_2 #import <musickit/musickit.h> #endif #ifdef NeXT_3 #import "/LocalDeveloper/Headers/musickit/musickit.h" #endif /* flags for writeParameters hackery */ #define writeParC 0 #define writeParLisp 1 #define writeParFreqName 2 #define writeParPreserveCase 4 static const char *const helpString = "Usage: mk2stella infile outfile\n"; static void writeScore(Score *aScore); static void writeHeader(Score *aScore); static void EnvelopesAndWaveTables(Score *aScore, List *aList); static void writeParts(Score *aScore); static void writeNotes(Part *aPart, unsigned modes); static void writeParameters(Note *aNote, unsigned modes); static char *genName(id obj, char *rootName); static NXStream *theStream; static FILE *fp; void main(int ac,char *av[]) { Score *aScore = [[Score alloc] init]; if (ac != 3) { fprintf(stderr,helpString); exit(1); } if (![aScore readScorefile:av[1]]) { fprintf(stderr,"mk2stella: Problem reading file.\n"); exit(1); } fp = fopen(av[2],"w"); theStream = NXOpenFile(fp->_file, NX_WRITEONLY); if (fp == NULL) { fprintf(stderr,"mk2stella: Problem opening output file.\n"); exit(1); } MKWritePitchNames(YES); NXPrintf(theStream,";;; written by mk2stella from %s\n",av[1]); writeScore(aScore); NXClose(theStream); fclose(fp); exit(0); } static void indent(int n) { int i; NXPrintf(theStream,"\n"); for (i=0;i<n;i++) NXPrintf(theStream," "); } static void writeScore(Score *aScore) { NXPrintf(theStream,"(in-package :stella)"); indent(0); NXPrintf(theStream,"(in-syntax :music-kit t)"); indent(0); NXPrintf(theStream,"((lambda (score)" ); /* print part definitions */ writeParts(aScore); indent(3); NXPrintf(theStream,"score)"); /* end lambda */ indent(1); NXPrintf(theStream,"(make-object 'merge :id '%s", genName(aScore, (char *)"score-%d" )); /* collect envelopes etc into a header string for score */ writeHeader(aScore); NXPrintf(theStream,"))\n"); /* end make-object, lambda form */ } static void writeParts(Score *aScore) /* Write part declarations and "part info" */ { List *parts = [aScore parts]; int i, partCount; if (!parts) return; indent(3); NXPrintf(theStream,"(add-objects"); indent(5); NXPrintf(theStream,"(list"); partCount = [parts count]; for (i=0; i<partCount; i++) { Part *aPart; Note *info; char *name, *class, useNames; BOOL freqNames = NO; int par, mode; aPart = (Part *)[parts objectAt:i]; name = (char *)MKGetObjectName(aPart); info = [aPart info]; /* if user specified freqNames:YES, print freqnames */ par=[Note parName:"freqNames"]; if ([info isParPresent:par] == YES) mode=writeParLisp | writeParFreqName; else mode=writeParLisp; class = (char *)[info parAsString:MK_synthPatch]; indent(7); NXPrintf(theStream,"((lambda (thread &aux info)"); indent(10); NXPrintf(theStream,"(setq info (partInfo \"%s\"", name); writeParameters(info, (writeParLisp | writeParPreserveCase)); NXPrintf(theStream,"))"); /* close partInfo, setq */ writeNotes(aPart, mode); indent(10); NXPrintf(theStream,"thread)"); /* close lambda */ indent(8); NXPrintf(theStream,"(make-object 'thread :id '%s))", name); } NXPrintf(theStream,")"); /* end list */ indent(5); NXPrintf(theStream,"score)"); /* end add-objects */ } static void writeNotes(Part *aPart, unsigned modes) { Note *info = [aPart info]; List *notes = [aPart notes]; char *name, *class; int i, noteCount; static char *noteTypeNames[] = {":noteDur",":noteOn",":noteOff", ":noteUpdate",":mute"}; Note *aNote, *nNote; MKNoteType nt; double r; if ((noteCount=[notes count])==0) return; name = (char *)MKGetObjectName(aPart); class = (char *)[info parAsString:MK_synthPatch]; indent(10); NXPrintf(theStream,"(add-objects"); indent(12); NXPrintf(theStream,"(list"); for (i=0;i<noteCount;i++) { aNote=(Note *)[notes objectAt:i]; if (i<(noteCount-1)) { nNote=(Note *)[notes objectAt:i+1]; r=[nNote timeTag] - [aNote timeTag]; } else r=0.0; nt = [aNote noteType]; indent(14); NXPrintf(theStream,"(make-object '%s :info info",class); NXPrintf(theStream," :rhythm %f",r); if ([aNote noteTag] != MAXINT) NXPrintf(theStream," :tag %d",[aNote noteTag]); if (nt == MK_noteDur) NXPrintf(theStream," :duration %f",[aNote dur]); else NXPrintf(theStream," :type '%s", noteTypeNames[nt-MK_noteDur]); writeParameters(aNote, modes); NXPrintf(theStream,")"); /* close make-object */ } NXPrintf(theStream,")"); /* close list */ indent(12); NXPrintf(theStream,"thread)"); /* close add-objects */ } static void writeHeader(Score *aScore) { List *aHeader = [[List alloc] init]; Note *info = [aScore info]; int i, envCount; char *name; id obj; EnvelopesAndWaveTables(aScore,aHeader); envCount = [aHeader count]; /* don't do anything if there are no header statements. */ if ((envCount == 0) && !info) return; indent(15); NXPrintf(theStream," :header \"\n"); if (info) { NXPrintf(theStream,"info "); writeParameters(info,writeParC); NXPrintf(theStream,";\n"); } for (i=0; i<envCount; i++) { obj = [aHeader objectAt:i]; if (!(name = (char *)MKGetObjectName(obj))) name = genName(obj, (char *)""); if ([obj class] == [Envelope class]) NXPrintf(theStream,"envelope %s = [",name); else NXPrintf(theStream,"waveTable %s = [",name); [obj writeScorefileStream:theStream]; NXPrintf(theStream,"];\n"); } NXPrintf(theStream,"\""); /* close header string */ [aHeader free]; } static void writeParameters(Note *aNote, unsigned modes) { void *aState; int par; char *name, *format; if ((modes & writeParLisp)==writeParLisp) if ((modes & writeParPreserveCase)==writeParPreserveCase) format=" :|%s|"; else format=" :%s"; else format="%s:"; aState = MKInitParameterIteration(aNote); while ((par = MKNextParameter(aNote,aState)) != MK_noPar) { name = [Note nameOfPar:par]; if (name[0] == (char)NULL) continue; /* skip private pars */ NXPrintf(theStream,format,name); if (((modes & writeParFreqName)==writeParFreqName) && ((strcmp([Note nameOfPar:par],"freq")==0) || (strcmp([Note nameOfPar:par],"freq0")==0))) { int keyNum = MKFreqToKeyNum([aNote parAsDouble:par], NULL,1.0); char *pitchNames[128] = { "c00","cs00","d00","ds00","e00","f00","fs00","g00","gs00","a00","as00","b00", "c0","cs0","d0","ds0","e0","f0","fs0","g0","gs0","a0","as0","b0", "c1","cs1","d1","ds1","e1","f1","fs1","g1","gs1","a1","as1","b1", "c2","cs2","d2","ds2","e2","f2","fs2","g2","gs2","a2","as2","b2", "c3","cs3","d3","ds3","e3","f3","fs3","g3","gs3","a3","as3","b3", "c4","cs4","d4","ds4","e4","f4","fs4","g4","gs4","a4","as4","b4", "c5","cs5","d5","ds5","e5","f5","fs5","g5","gs5","a5","as5","b5", "c6","cs6","d6","ds6","e6","f6","fs6","g6","gs6","a6","as6","b6", "c7","cs7","d7","ds7","e7","f7","fs7","g7","gs7","a7","as7","b7", "c8","cs8","d8","ds8","e8","f8","fs8","g8","gs8","a8","as8","b8", "c9","cs9","d9","ds9","e9","f9","fs9","g9"}; NXPrintf(theStream," '%s",pitchNames[keyNum]); } else switch ([aNote parType:par]) { case MK_envelope: case MK_waveTable: NXPrintf(theStream," \"%s\"", MKGetObjectName([aNote parAsObject:par])); break; case MK_double: NXPrintf(theStream," %f", [aNote parAsDouble:par]); break; case MK_int: NXPrintf(theStream," %d",[aNote parAsInt:par]); break; case MK_string: NXPrintf(theStream," \"%s\"", [aNote parAsStringNoCopy:par]); break; default: break; } } } static char *genName(id obj, char *rootName) { static char name[64]; int i; if (rootName==(char *)"") rootName=(char *)"obj%d" ; sprintf(name, rootName,obj); i = 0; while (MKGetNamedObject(name)) { i++; sprintf(name, rootName,obj+i); } MKNameObject(name,obj); /* Copies string */ return name; } static void EnvelopesAndWaveTables(Score *aScore, List *allEnvsAndWaves) /* Dig through notes and find all envelopes and wave tables. Give them names, if necessary, and put them in the header. */ { List *parts = [aScore parts]; Part *aPart; List *notes; Note *aNote; char *name; id obj; int i,partCount,j,noteCount; int par; void *aState; if (!parts) return; partCount = [parts count]; for (i=0; i<partCount; i++) { aPart = (Part *)[parts objectAt:i]; notes = [aPart notes]; if (notes) { noteCount = [notes count]; for (j=0; j<noteCount; j++) { aNote = [notes objectAt:j]; aState = MKInitParameterIteration(aNote); while ((par = MKNextParameter(aNote,aState)) != MK_noPar) { obj = [aNote parAsObject:par]; if (obj != nil) { if ([allEnvsAndWaves indexOf:obj] == NX_NOT_IN_LIST) { [allEnvsAndWaves addObject:obj]; } } } } [notes free]; } } [parts free]; /* Free list. */ }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.