Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
•QTMusic Sample Sequencer/SequencerTest Realtime.c
/* |
* file: SequencerTest Realtime.c |
* |
* |
*/ |
/*-------------------------- |
Inclusions |
--------------------------*/ |
#include <QuickDraw.h> |
#include <Windows.h> |
#include <Memory.h> |
#include <Packages.h> |
#include "BigEasy2.h" |
#include "BigEasyTextish.h" |
#include "BigEasyGrafish.h" |
#include "BigEasyDialogs.h" |
#include "SequencerTest.h" |
#include "SequencerTest Realtime.h" |
#include "Event Priority Queue.h" |
/*-------------------------- |
Local Prototypes |
--------------------------*/ |
static void DelayXUnits(long x, long units); |
static short GetPipDuration(ScorePart *sp,short x,short y); |
static void PrerollDoc(TDoc *d); |
/*-------------------------- |
The Bronx Zoo |
--------------------------*/ |
void PlayScorePartBeat(ScorePart *sp, NoteChannel nc, short beat) |
{ |
unsigned long thisMask,lastMask; |
short thisElementH,lastElementH; |
short elementV; |
Boolean thisPip,lastPip; |
ComponentResult thisError; |
thisMask = 1L << (beat & 31); |
thisElementH = beat / 32; |
lastMask = 1L << (( (beat + kScoreLength - 1) % kScoreLength) & 31); |
lastElementH = ( (beat + kScoreLength - 1) % kScoreLength) / 32; |
for(elementV = 0; elementV < kScoreHeight; elementV++) |
{ |
if(beat == kScoreLength) |
thisPip = 0; |
else |
thisPip = 0 != (sp->score[elementV][thisElementH] & thisMask); |
if(beat == 0) |
lastPip = 0; |
else |
lastPip = 0 != (sp->score[elementV][lastElementH] & lastMask); |
if(thisPip && !lastPip) |
{ |
thisError = NAPlayNote(g.na,nc,kNoteRangeHigh - elementV, 64); |
ShowError(thisError); |
} |
else if(lastPip && !thisPip) |
{ |
thisError = NAPlayNote(g.na,nc,kNoteRangeHigh - elementV, 0); |
ShowError(thisError); |
} |
} |
} |
void PrerollDoc(TDoc *d) |
{ |
short j; |
ComponentResult thisError; |
#ifdef separateNoteChannel |
for(j = 0; j<kScoreParts; j++) |
{ |
thisError = NAPrerollNoteChannel(g.na,d->noteChannel[j]); |
ShowError(thisError); |
} |
#endif |
thisError = TunePreroll(d->tp); |
ShowError(thisError); |
} |
void PlayDocOnce(TDoc *d) |
{ |
short beat,j; |
long dummy; |
Boolean oldEngage,newEngage; |
ComponentResult thisError; |
PrerollDoc(d); |
oldEngage = true; |
for(beat = 0; beat < kScoreLength; beat ++) |
{ |
newEngage = !Button(); |
if(newEngage != oldEngage) |
{ |
if(newEngage) |
for(j = 0; j < kScoreParts; j++) |
{ |
thisError = NAEngageNoteChannel(g.na,d->noteChannel[j]); |
ShowError(thisError); |
} |
else |
for(j = 0; j < kScoreParts; j++) |
{ |
thisError = NADisengageNoteChannel(g.na,d->noteChannel[j],true); |
ShowError(thisError); |
} |
oldEngage = newEngage; |
} |
for(j = 0; j<kScoreParts; j++) |
PlayScorePartBeat(&d->sr.score[j],d->noteChannel[j],beat); |
Delay(6,&dummy); |
} |
for(j = 0; j<kScoreParts; j++) |
PlayScorePartBeat(&d->sr.score[j],d->noteChannel[j],kScoreLength); |
for(j = 0; j < kScoreParts; j++) |
{ |
thisError = NAEngageNoteChannel(g.na,d->noteChannel[j]); |
ShowError(thisError); |
} |
} |
short GetPipDuration(ScorePart *sp,short x,short y) |
{ |
short d; |
d = x; |
while(x < kScoreLength && GetPipBit(sp,x,y)) |
x++; |
d = x - d; |
return d; |
} |
void ScoreToQTScore(TDoc *d) |
{ |
long i,x,y; |
ScorePart *sp; |
short lastGoodX; |
long duration; |
long time; |
long deltaTime; |
long *w; |
long timeScalar; |
timeScalar = 1; |
if(d->qtScore) |
DisposeHandle(d->qtScore); |
d->qtScore = NewHandle(40000); |
HLock(d->qtScore); |
w = (void *)*d->qtScore; |
lastGoodX = 0; |
for(x = 0; x < kScoreLength; x++) |
{ |
for (i = 0; i < kScoreParts; i++) |
{ |
sp = &d->sr.score[i]; |
for (y = 0; y < kScoreHeight; y++) |
{ |
if(GetPipBit(sp,x,y) |
&& (x == 0 || !GetPipBit(sp,x-1,y))) |
{ |
if(x > lastGoodX) /* emit rest if necessary */ |
{ |
duration = timeScalar * (x - lastGoodX); |
*w++ = duration; |
lastGoodX = x; |
} |
/* |
* emit note event |
*/ |
duration = timeScalar * GetPipDuration(sp,x,y); |
*w++ = 0x20000000 | (i << 24) |
| ((kNoteRangeHigh - y - 32) << 18) |
| (90L << 11) |
| duration; |
} |
} |
} |
} |
duration = timeScalar * (kScoreLength - lastGoodX); |
if(duration) |
*w++ = duration; |
*w++ = 0x60000000; |
*w++ = -1; |
SetHandleSize(d->qtScore,((char *)w) - ((char *)*d->qtScore)); |
d->validQTScore = true; |
} |
void DelayXUnits(long x, long units) |
{ |
long dummy; |
if(x < 0) |
Debugger(); |
Delay(x * 60 / units, & dummy); |
} |
typedef enum |
{ |
qNoteOff, |
qSleep |
} qCommand; |
void PlayQTScore(TDoc *d) |
{ |
Handle qtScore; |
long *qtScorePtr; |
long *w; |
unsigned short command; |
unsigned long op1,op2,op3,op4; |
EPQ *q; |
EPQEvent e; |
long timeNow; |
long nextDelay; |
ComponentResult thisError; |
unsigned short instrument,pitch,velocity; |
long duration; |
short controller,value; |
PrerollDoc(d); |
if(!d->validQTScore) |
ScoreToQTScore(d); |
qtScore = d->qtScore; |
HLock(qtScore); |
qtScorePtr = (void *)*qtScore; |
q = NewEPQ(2000); |
w = qtScorePtr; |
timeNow = 0; |
while(1) |
{ |
op1 = *w++; |
if(op1 == 0xFFFFffff) |
goto done; |
command = op1>>29; |
if(command == 0) /* rest */ |
{ |
e.time = timeNow + op1; |
e.data1 = qSleep; |
AddEventEPQ(q,&e); |
do |
{ |
ExtractEventEPQ(q,&e); |
if(e.time != timeNow) |
DelayXUnits(e.time - timeNow,600); |
timeNow = e.time; |
if(e.data1 == qNoteOff) |
{ |
thisError = NAPlayNote(g.na,d->noteChannel[e.data2],e.data3,0); |
ShowError(thisError); |
} |
} while(GetSizeEPQ(q) && e.data1 != qSleep); |
while(GetSizeEPQ(q) != 0 && PeekTopEPQ(q) == timeNow) |
{ |
ExtractEventEPQ(q,&e); |
if(e.data1 == qNoteOff) |
{ |
thisError = NAPlayNote(g.na,d->noteChannel[e.data2],e.data3,0); |
ShowError(thisError); |
} |
}; |
} |
else if (command == 1) |
{ |
instrument = (op1 >> 24) & 31; |
pitch = ((op1 >> 18) & 63) + 32; |
velocity = (op1>>11) & 127; |
duration = op1 & 0x03FF; |
thisError = NAPlayNote(g.na,d->noteChannel[instrument],pitch,velocity); |
ShowError(thisError); |
e.time = timeNow + duration; |
e.data1 = qNoteOff; |
e.data2 = instrument; |
e.data3 = pitch; |
AddEventEPQ(q,&e); |
} |
} |
done: |
DisposeEPQ(q); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-03-19