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.