•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);
 
    }