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.