This is ClmCodeGen.m in view mode; [Download] [Up]
/**************************************************
* SynthBuilder
* Copyright 1993 Nick Porcaro All Rights Reserved
**************************************************/
/*
* ClmCodeGen.m
* Nick Porcaro and Owen Smith Spring/Summer 1993
*
* This is the clm related stuff taken out of FakeSynthPatch.m
*/
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
#import <math.h>
#import <appkit/Application.h>
#import <appkit/Control.h>
#import <appkit/Matrix.h>
#import <appkit/Panel.h>
#import <appkit/OpenPanel.h>
#import <appkit/SavePanel.h>
#import "FakeSynthPatch.h"
#import "FakePatchPoint.h"
#import "FakeUG.h"
#import "ClmCodeGen.h"
#define MAXMESSAGELENGTH 200
// Added by Owen
#define GetNextUG(n) [[[theUG getConnection:n] getFromNode] superview]
#define MAXENVSTRING 100
// Added by Owen
static BOOL IsInitializeable(char *s);
static BOOL MultipleOuts(id theUG);
static void DefineBlock(FILE *f, id theUG, id definedList);
static void NextCrunch(FILE *f, id theUG, id definedList, int connection);
static void PrintCrunch(FILE *f, id theUG, id definedList);
static char *ParseEnvString(char *s, double dur);
static int GetNumberOfInputs(id theUG);
static char TempString[1024];
extern id savePanel;
extern id openPanel;
extern char *getSavePath(char *banner);
extern char *getOpenPath(char *banner);
extern char *getAppName();
@implementation ClmCodeGen
- init
{
[super init];
[NXApp loadNibSection:"ClmCodeGen.nib" owner:self withNames:YES];
return self;
}
- setSP:aSP
{
theSP = aSP;
fakeUGs = [theSP getFakeUGs];
fakePatchPoints = [theSP getFakePatchPoints];
return self;
}
- displayInspector:sender
{
[theInspector makeKeyAndOrderFront:self];
return self;
}
- emitCode:sender
{
char *file_name;
sprintf(TempString, "%s Generate CLM code", getAppName());
if (! (file_name = getSavePath(TempString)))
{
return self;
}
[self makeLispCode: file_name
samplingRate: [theSamplingRate doubleValue]
instrumentName: (char *) [theInstrName stringValue]
startTime: [theStartTime doubleValue]
duration: [theDuration doubleValue]
];
/* Now do the right thing with the file */
switch ([[patchDest selectedCell] tag])
{
case(0):
{
sprintf(TempString, "open %s", file_name);
system(TempString);
}
case(1):
{
NXRunAlertPanel(getAppName(), "Paste Board not supported yet", NULL, NULL, NULL);
break;
}
case(2):
{
sprintf(TempString, "%s %s &",
[testerScript stringValue], file_name);
printf("Shell command: %s\n", TempString);
system(TempString);
break;
}
}
return self;
}
- makeLispCode: (char *) aFileName
samplingRate: (double) aSamplingRate
instrumentName: (char *) anInstrumentName
startTime: (double) aStartTime
duration: (double) aDuration
{
int i;
id theUG;
char *ug_name, *ug_type;
int method_count = 0;
int pointCount=0, stickPoint = -1;
int envelopes_processed = 0;
FILE *f;
extern char *getenv();
char *ptr;
char *fileName;
double samplingRate;
char *instrumentName;
double startTime;
double duration;
// isDefined is a list of the names of all the defined multiple-output
// synth blocks in the patch for the run-time loop. A better way would be
// to tack on another BOOL field to the FakeUG definition, saying whether
// or not a particular instance of a FakeUG has been defined or not.
id isDefined = [[List alloc] init];
fileName = aFileName;
samplingRate = aSamplingRate;
instrumentName = anInstrumentName;
startTime = aStartTime;
duration = aDuration;
// Open file
f = fopen(fileName, "w");
if (!f)
{
NXRunAlertPanel("Emit Code", "Can't create file.", NULL, NULL, NULL);
return self;
}
// Get the parameters
ptr = (char *) [theSP getName];
if (ptr)
{
strcpy(instrumentName, ptr);
}
// Put out file header
fprintf(f, ";;; -*- Syntax: Common-Lisp; Package: COMMON-MUSIC; Base: 10; Mode: Lisp -*-\n\n");
fprintf(f, ";;; Instrument: %s; Part: %s\n;;; Created by %s for CLM\n\n",
instrumentName, instrumentName, getAppName());
// init stuff
fprintf(f, "(in-package 'common-music)\n(in-syntax ':clm)\n\n");
fprintf(f, "(definstrument %s (&key\n", instrumentName); // add params someday?
fprintf(f, " (start-time %g)\n", startTime);
fprintf(f, " (duration %g)\n", duration);
fprintf(f, " (amplitude 0.5))\n\n");
// initialize UGs. beg and end are the start and end time in samples.
fprintf(f, " (let* ((beg (floor (* start-time sampling-rate)))\n");
fprintf(f, " (end (+ beg (floor (* duration sampling-rate))))\n");
fprintf(f, " (freq-tweak %g)\n", 8 * atan(1)); // since internal table size is 2Pi?
// loop to initialize the actual UGs. Loop goes through all the patchpoints and accesses the UGs through them.
// There is definitely a better way, but...
for (i=0; i<[fakeUGs count]; i++)
{
theUG = [fakeUGs objectAt:i];
ug_type = [theUG getGenericTypeString];
if ((ug_type != NULL) && (IsInitializeable(ug_type)))
{
ug_name = [theUG getName];
fprintf(f, " (%s", ug_name);
if (! strcmp(ug_type, "Out2sumUG")) fprintf(f, " (make-locsig))\n");
else if (! strcmp(ug_type, "Out1aUG")) fprintf(f, " (make-locsig :degree -90))\n");
else if (! strcmp(ug_type, "Out1bUG")) fprintf(f, " (make-locsig :degree 90))\n");
else if (! (strcmp(ug_type, "OscgafUG") && strcmp(ug_type, "OscgafiUG")))
{
fprintf(f, " (make-oscil :frequency 0.0 :initial-phase 0.0))\n");
}
else if (! strcmp(ug_type, "Constantpp")) fprintf(f, " %g)\n", atod([theUG getConstant]));
else if (! strcmp(ug_type, "ConstantUG")) fprintf(f, " %g)\n", atod([theUG getArg:0]));
else if (! strcmp(ug_type, "DelayUG")) fprintf(f, " (make-delay %d))\n", atoi([theUG getArg:0]));
// We should check with Julius about these filters and the "InterpUG".
else if (! strcmp(ug_type, "Allpass1UG"))
{
fprintf(f, " (make-all-pass #| feedback-scaler feedforward-scaler length |#))\n");
}
else if (! strcmp(ug_type, "OnepoleUG"))
{
fprintf(f, " (make-one-pole %g %g))\n", atod([theUG getArg:0]), atod([theUG getArg:1]));
}
else if (! strcmp(ug_type, "OnezeroUG"))
{
fprintf(f, " (make-one-zero %g %g))\n", atod([theUG getArg:0]), atod([theUG getArg:1]));
}
else if (! strcmp(ug_type, "OscgUG"))
{
fprintf(f, " (make-oscil :frequency %g :initial-phase %g))\n", atod([theUG getArg:1]), atod([theUG getArg:3]));
}
else if (! strcmp(ug_type, "oscilUG"))
{
fprintf(f, " (make-oscil :frequency %g :initial-phase %g))\n", atod([theUG getArg:0]), atod([theUG getArg:1]));
}
else if (! strcmp(ug_type, "ScaleUG")) fprintf(f, " %g)\n", atod([theUG getArg:0]));
else if (! strcmp(ug_type, "Scl1add2UG")) fprintf(f, " %g)\n", atod([theUG getArg:0]));
else if (! strcmp(ug_type, "Scl2add2UG"))
{
fprintf(f, "-1 %g)\n (%s-2 %g)\n", atod([theUG getArg:0]), ug_name, atod([theUG getArg:1]));
}
else if (! strcmp(ug_type, "SnoiseUG")) fprintf(f, " (make-randh))\n");
else if (! strcmp(ug_type, "UnoiseUG")) fprintf(f, " (make-randi))\n");
else if (! strcmp(ug_type, "AsympUG"))
{
fprintf(f, " (make-env :envelope '%s :start-time start-time :duration duration))\n",
ParseEnvString([theUG getArg:4], duration));
}
}
if ((ug_type != NULL) && (MultipleOuts(theUG) && strcmp(ug_type, "SineROM") && strcmp(ug_type, "Storage")))
{
ug_name = [theUG getName];
fprintf(f, " (%s-out 0.0)\n", ug_name);
}
}
fprintf(f, " )\n\n");
// now for the run-time loop
fprintf(f, " (set-srate %g)\n", samplingRate);
fprintf(f, " (Run\n");
fprintf(f, " (loop for i from beg to end do\n ");
for (i=0; i<[fakeUGs count]; i++)
{
if (! [[fakeUGs objectAt:i] getConnectionName:0])
{
DefineBlock(f, [fakeUGs objectAt:i], isDefined);
PrintCrunch(f, [fakeUGs objectAt:i], isDefined);
}
}
fprintf(f, "\n )\n )\n (end-run)\n ))\n\n");
// defpart
fprintf(f, "(defpart %s (clm-part)\n", instrumentName);
fprintf(f, " (name &message start-time duration amplitude)\n");
fprintf(f, " (start-time duration amplitude))\n\n");
// sample score file
fprintf(f, "#|\n; Sample score file for instrument %s and part %s\n\n", instrumentName, instrumentName);
fprintf(f, "(defscorefile (after '(load :srate %g :channels 2))\n", samplingRate);
fprintf(f, " (with-part %s (time 0.0 events 1)))\n", instrumentName);
fprintf(f, "|#\n");
fclose(f);
return self;
}
@end
static BOOL IsInitializeable(char *s)
{
// If s is equal to any of these strings, NO is returned.
return (strcmp(s, "Add2UG") && strcmp(s, "DswitchUG") && strcmp(s, "DswitchtUG") && strcmp(s, "Mul1add2UG")
&& strcmp(s, "Mul2UG") && strcmp(s, "SineROM") && strcmp(s, "Storage"));
}
static BOOL MultipleOuts(id theUG)
{
// If the UG passed in has more than one output, YES is returned.
id theOut;
return ((theOut = [theUG getConnection:0]) ? ([[theOut getToNodes] count] > 1) : NO);
}
static void DefineBlock(FILE *f, id theUG, id definedList)
{
int i;
if (! MultipleOuts(theUG))
{
// recurse through all the inputs
for (i=1; i <= GetNumberOfInputs(theUG); i++)
{
DefineBlock(f, GetNextUG(i), definedList);
}
}
else
{
if (strcmp([theUG getGenericTypeString], "Storage") && strcmp([theUG getGenericTypeString], "SineROM"))
{
if ([definedList indexOf:theUG] == NX_NOT_IN_LIST)
{
// add the UG to the list of defined synth blocks
[definedList addObject:theUG];
// recurse through all the inputs
for (i=1; i <= GetNumberOfInputs(theUG); i++)
{
DefineBlock(f, GetNextUG(i), definedList);
}
fprintf(f, "(setf %s-out ", [theUG getName]);
PrintCrunch(f, theUG, definedList);
fprintf(f, ")\n ");
}
}
}
}
static void NextCrunch(FILE *f, id theUG, id definedList, int connection)
{
id nextUG;
nextUG = GetNextUG(connection);
if (MultipleOuts(nextUG))
{
if ([definedList indexOf:nextUG] == NX_NOT_IN_LIST)
{
fprintf(f, "\n ERROR: No definition for synthblock %s-out\n", [nextUG getName]);
}
else fprintf(f, "%s-out", [nextUG getName]);
}
else PrintCrunch(f, nextUG, definedList);
}
static void PrintCrunch(FILE *f, id theUG, id definedList)
{
char *type = [theUG getGenericTypeString];
if (! strcmp(type, "Add2UG"))
{
fprintf(f, "(+ ");
NextCrunch(f, theUG, definedList, 1);
fprintf(f, " ");
NextCrunch(f, theUG, definedList, 2);
fprintf(f, ")");
}
else if (! strcmp(type, "AsympUG"))
{
fprintf(f, "(env %s)", [theUG getName]);
}
else if (! strcmp(type, "Allpass1UG"))
{
fprintf(f, "(all-pass %s ", [theUG getName]);
NextCrunch(f, theUG, definedList, 1);
fprintf(f, ")");
}
else if (! (strcmp(type, "ConstantUG") && strcmp(type, "Constantpp")))
{
fprintf(f, "%s", [theUG getName]);
}
else if (! strcmp(type, "DelayUG"))
{
fprintf(f, "(delay %s ", [theUG getName]);
NextCrunch(f, theUG, definedList, 1);
fprintf(f, ")");
}
else if (! strcmp(type, "Mul2UG"))
{
fprintf(f, "(* ");
NextCrunch(f, theUG, definedList, 1);
fprintf(f, " ");
NextCrunch(f, theUG, definedList, 2);
fprintf(f, ")");
}
else if (! strcmp(type, "OnepoleUG"))
{
fprintf(f, "(one-pole %s ", [theUG getName]);
NextCrunch(f, theUG, definedList, 1);
fprintf(f, ")");
}
else if (! strcmp(type, "OnezeroUG"))
{
fprintf(f, "(one-zero %s ", [theUG getName]);
NextCrunch(f, theUG, definedList, 1);
fprintf(f, ")");
}
else if (! strcmp(type, "OscgUG"))
{
fprintf(f, "(oscil %s)", [theUG getName]);
}
else if (! (strcmp(type, "OscgafUG") && strcmp(type, "OscgafiUG")))
{
fprintf(f, "(* ");
NextCrunch(f, theUG, definedList, 1); // amp input
fprintf(f, " (oscil %s (* freq-tweak ", [theUG getName]);
NextCrunch(f, theUG, definedList, 2); // phase inc. input
fprintf(f, ")))");
}
else if (! (strcmp(type, "Out1aUG") && strcmp(type, "Out1bUG") && strcmp(type, "Out2sumUG")))
{
fprintf(f, "(locsig %s i (* amplitude ", [theUG getName]);
NextCrunch(f, theUG, definedList, 1);
fprintf(f, "))");
}
else if (! strcmp(type, "Scl1add2UG"))
{
fprintf(f, "(+ (* %s ", [theUG getName]);
NextCrunch(f, theUG, definedList, 1);
fprintf(f, ") ");
NextCrunch(f, theUG, definedList, 2);
fprintf(f, ")");
}
else if (! strcmp(type, "Scl2add2UG"))
{
fprintf(f, "(+ (* %s-1 ", [theUG getName]);
NextCrunch(f, theUG, definedList, 1);
fprintf(f, ") (* %s-2 ", [theUG getName]);
NextCrunch(f, theUG, definedList, 2);
fprintf(f, "))");
}
else if (! strcmp(type, "SnoiseUG"))
{
fprintf(f, "(randh %s)", [theUG getName]);
}
else if (! strcmp(type, "UnoiseUG"))
{
fprintf(f, "(randi %s)", [theUG getName]);
}
else if (! strcmp(type, "oscilUG"))
{
fprintf(f, "(oscil %s (* freq-tweak ", [theUG getName]);
NextCrunch(f, theUG, definedList, 1);
fprintf(f, "))");
}
else fprintf(f, "\n I don't know how to handle this UG yet: %s\n", type);
}
static char *ParseEnvString(char *s, double dur)
{
int i, j, bkptnum;
BOOL isSticker = NO;
char *parsed, *numpair, *final;
double *xPts, *yPts;
int stickIndex=0, parseLength;
double endTime, susTime, newx;
for (i=0, bkptnum=0; s[i] != '\0'; i++)
{
if (s[i] == '|') isSticker = YES;
if (s[i] == '(') bkptnum++;
}
xPts = (double*) malloc(bkptnum*sizeof(double));
yPts = (double*) malloc(bkptnum*sizeof(double));
parsed = (char *) malloc(MAXENVSTRING*sizeof(char));
numpair = (char *) malloc(30*sizeof(char));
for (i=0, j=0; s[i] != '\0'; i++)
{
if (s[i] == '(')
{
sscanf(s+i, "(%lf, %lf)", &xPts[j], &yPts[j]);
j++;
}
if (s[i] == '|') stickIndex = j;
}
endTime = xPts[j-1];
if (! (isSticker && (dur > endTime)))
{
sprintf(parsed, "(");
for (i=0; i < bkptnum; i++)
{
sprintf(numpair, "%g %g ", xPts[i], yPts[i]);
strcat(parsed, numpair);
}
strcat(parsed, ")");
}
else
{
susTime = dur - endTime;
sprintf(parsed, "(");
for (i=0; i < stickIndex; i++)
{
sprintf(numpair, "%g %g ", xPts[i], yPts[i]);
strcat(parsed, numpair);
}
i--;
newx = xPts[i] + susTime;
sprintf(numpair, "%g %g ", newx, yPts[i]);
strcat(parsed, numpair);
i++;
while (i < bkptnum)
{
newx = xPts[i] + susTime;
sprintf(numpair, "%g %g ", newx, yPts[i]);
strcat(parsed, numpair);
i++;
}
strcat(parsed, ")");
}
parseLength = strlen(parsed);
final = (char *) malloc(parseLength*sizeof(char));
strcpy(final, parsed);
free(parsed);
free(numpair);
return parsed;
}
static int GetNumberOfInputs(id theUG)
{
int i;
// all inputs start at connection index 1.
// if there is no name for the connection,
// then the connection does not exist.
for (i=1; [theUG getConnectionName:i]; i++);
return (i-1);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.