This is playscorefile2.m in view mode; [Download] [Up]
/*
playscorefile2.
David A. Jaffe.
See README for a description of this program.
*/
/* playscorefile2 is an example of a Music Kit performance that "spools" a
scorefile to the DSP. Since no real-time interaction is involved, all
timing is done on the DSP; thus, the Orchestra is set to timed mode and the
Conductor is set to unclocked mode. In unclocked mode the Conductor's
+startPerformance method initiates a tight loop that sends Notes as
fast as possible until all Notes have been sent, then returns. */
#import <musickit/musickit.h>
#import <musickit/synthpatches/synthpatches.h>
static int handleObjcError(char *className)
{ return 0; }
main(ac, av)
int ac;
char * av[];
{
int i;
id aSFPerformer,anOrch;
[UnitGenerator enableErrorChecking:YES]; /* Added for debugging purposes */
for (i=1; i<ac; i++) {
/* Read command line arguments. Usage: [-t <num> < <file>] */
if (av[i][1] == 't')
MKSetTrace(atoi(av[++i]));
}
if (isatty(0)) {
fprintf(stderr,"usage: playscorefile2 [-t] < inputfile\n");
exit(1);
}
{ /* Create a Score object and read a scorefile into it. Then create a
ScorePerformer to perform the Score and configure the performance
from the 'info' field of the scorefile . */
id scoreInfo; /* Used for 'info' */
NXStream *stdinStream = NXOpenFile(stdin->_file,NX_READONLY);
aSFPerformer = [[ScorefilePerformer alloc] init];
[aSFPerformer setStream:stdinStream];
[aSFPerformer activate];
scoreInfo = [aSFPerformer info];
if (scoreInfo) { /* Configure performance as specified in info. */
/* "headroom" determines how close to the limit of the DSP we want
to run. If headroom is 0 or negative, there is a higher risk
of falling out of real time (interruptions will be heard).
If headroom is positive (e.g. .25), it is unlikely you will
fall out of real time. */
if ([scoreInfo isParPresent:MK_headroom])
[Orchestra setHeadroom:[scoreInfo parAsDouble:MK_headroom]];
/* Set sampling rate. The Sound hardware only functions at
44100 or 22050. */
if ([scoreInfo isParPresent:MK_samplingRate]) {
double samplingRate = [scoreInfo parAsDouble:MK_samplingRate];
if ((samplingRate == 44100.0) || (samplingRate == 22050.0))
[Orchestra setSamplingRate:samplingRate];
else fprintf(stderr,
"Sampling rate must be 44100 or 22050.\n");
}
/* Get tempo and set the tempo of the default Conductor. */
if ([scoreInfo isParPresent:MK_tempo]) {
double tempo = [scoreInfo parAsDouble:MK_tempo];
[[Conductor defaultConductor] setTempo:tempo];
}
}
}
/* Open the Orchestra. */
anOrch = [Orchestra new];
if (![anOrch open]) {
fprintf(stderr,"Can't open DSP.\n");
exit(1);
}
{ /* Create a SynthInstrument for each part in the scorefile and set them
up as specified in the corresponding 'info'. Each part in the
scorefile has a corresponding NoteSender in the ScorefilePerformer */
int partCount,synthPatchCount,voices;
char *className;
id noteSenders,synthPatchClass,partInfo,anIns,aNoteSender;
noteSenders = [aSFPerformer noteSenders];
partCount = [noteSenders count];
for (i = 0; i < partCount; i++) {
aNoteSender = [noteSenders objectAt:i];
partInfo = [aSFPerformer infoForNoteSender:aNoteSender];
if (!partInfo) { /* Omit Parts with no info. */
fprintf(stderr,"%s info missing.\n",
MKGetObjectName(aNoteSender));
continue;
}
/* Look in the partInfo for a SynthPatch name. If none, omit
this part. */
if (![partInfo isParPresent:MK_synthPatch]) {
fprintf(stderr,"%s info missing synthPatch.\n",
MKGetObjectName(aNoteSender));
continue;
}
/* Now set the SynthPatch of this part as specified in the info */
className = [partInfo parAsStringNoCopy:MK_synthPatch];
/* We find the class. */
objc_setClassHandler(handleObjcError); /* Supress error printing */
synthPatchClass = (strlen(className) ?
objc_getClass(className) : nil);
if (!synthPatchClass) { /* Class not loaded in program? */
fprintf(stderr,"Class %s not loaded into program.\n",
className);
continue;
}
/* Create a new SynthInstrument to manage the notes from this part
and connect the noteSender to the SynthInsturment's
noteReceiver. */
anIns = [[SynthInstrument alloc] init];
[aNoteSender connect:[anIns noteReceiver]];
/* Set the new SynthInstrument to use the specified SynthPatch */
[anIns setSynthPatchClass:synthPatchClass];
/* Look for the synthPatchCount for this part. */
if (![partInfo isParPresent:MK_synthPatchCount])
continue; /* Do allocation of voices from a common pool
on the fly during performance. */
/* Otherwise, use a number of voices specified by the part info.*/
voices = [partInfo parAsInt:MK_synthPatchCount];
synthPatchCount =
[anIns setSynthPatchCount:voices patchTemplate:
[synthPatchClass patchTemplateFor:partInfo]];
/* A given SynthPatch can have several versions or
"PatchTemplates". For example, there may be one version
that supports vibrato and another that does not.
The SynthPatch class provides a method to
determine the correct version for a given Note. In this case,
we pass the SynthPatch class the Part info and allow it
to customize based on the information contained therein. */
if (synthPatchCount < voices)
fprintf(stderr,
"Could only allocate %d instead of %d %ss for %s\n",
synthPatchCount,voices,[synthPatchClass name],
MKGetObjectName(aNoteSender));
}
}
/* Prepare Conductor */
MKSetDeltaT(1.0); /* Run at least one second ahead of DSP.
For very dense scores, this number may
have to be increased. */
[Conductor setClocked:NO]; /* Conductor feeds DSP as fast as it can. */
[Conductor setThreadPriority:1.0]; /* Boost priority of performance. */
[anOrch run]; /* Start the DSP. */
fprintf(stderr,"playing...\n");
[Conductor startPerformance]; /* Start sending Notes, loops till done.*/
/* Here's where the music plays. Conductor's startPerformance method
does not return until the performance is over. Note, however, that
if the Conductor is in a different mode, startPerformance returns
immediately (if it is in clocked mode or if you have specified that the
performance is to occur in a separate thread). See the Conductor
documentation for details.
*/
/* Now clean up. */
[anOrch close]; /* Releases DSP. */
fprintf(stderr,"...done\n");
exit(0);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.