•Instrument Editor/IE KeyboardDiagram.c

/*
    File:       KeyboardDiagram.c
 
    Modified version from the one in the warhol project
 
*/
 
 
#include <Memory.h>
#include <QuickDraw.h>
#include <Resources.h>
#include "IE KeyboardDiagram.h"
 
static Handle GetAndDetachResource(ResType type,short id);
 
#define kBlackKeyBottom 16
 
static Handle GetAndDetachResource(ResType type,short id)
    {
    Handle h;
 
    h = GetResource(type,id);
    DetachResource(h);
    return h;
    }
 
void InitializeKeyboard(KeyboardDiagram *kd,Rect *r,short octaveCount,short lowKey)
    {
    short i;
 
    kd->r = *r;
    kd->octaveCount = octaveCount;
    kd->keyCount = octaveCount * 12;
 
    if(lowKey >= 128)
        {
        kd->mod = true;
        kd->modOffset = ((lowKey + kd->keyCount - 1) / kd->keyCount) * kd->keyCount;
        lowKey &= 127;
        }
    else
        kd->mod = false;
 
    kd->lowKey = lowKey;
 
    for(i = 0; i < 128; i++)
        kd->keyVel[i] = 0;
 
    kd->whiteKey = (short **)GetAndDetachResource('Junk',kJunkWhite);
    kd->keyRight = (short **)GetAndDetachResource('Junk',kJunkBlack);
    }
 
void TerminateKeyboard(KeyboardDiagram *kd)
    {
    DisposeHandle((Handle)kd->whiteKey);
    DisposeHandle((Handle)kd->keyRight);
    }
 
void SetKeyboardTopLeft(KeyboardDiagram *kd,short top, short left)
    {
    OffsetRect(&kd->r, left - kd->r.left, top - kd->r.top);
    }
 
void DrawKeyboardPiece(KeyboardDiagram *kd, short octave)
    {
    Rect r;
    short w;
    PicHandle pH;
 
    PenNormal();
 
    pH = (PicHandle)Get1Resource('PICT',kKeyboardPict);
    if(pH)
        {
        r = (**pH).picFrame;
        w = r.right - r.left-1;
        OffsetRect(&r,kd->r.left - r.left + w * octave,kd->r.top - r.top);
        DrawPicture(pH,&r);
    
        if(kd->gray)
            {
            GoGray();
            PenMode(patBic);
            r.right += 2;
            r.bottom += 2;
            PaintRect(&r);
            PenNormal();
            }
        }
    }
 
 
void DrawKeyboardDropShadow(KeyboardDiagram *kd)
    {
    MoveTo(kd->r.left + 3,kd->r.bottom);
    LineTo(kd->r.right,kd->r.bottom);
    LineTo(kd->r.right,kd->r.top + 3);
    }
 
void DrawKeyboard(KeyboardDiagram *kd)
    {
    short i;
 
    DrawKeyboardDropShadow(kd);
    for(i = 0; i < kd->octaveCount; i++)
        DrawKeyboardPiece(kd,i);
    }
 
void SetKeyboardGray(KeyboardDiagram *kd,Boolean gray)
    {
    if(kd->gray != gray)
        {
        kd->gray = gray;
        DrawKeyboard(kd);
        }
    }
 
 
 
void PaintKeyboardKey(KeyboardDiagram *kd,short pitch,short gray)
/* 
 * 0-255, gray; -1, invert; -2, forecolor
 */
    {
    short i,k;
    short octave;
    Rect r1,r2;
    Boolean blackKey;
 
    if(kd->gray)
        goto goHome;
 
 
    r1.left = r1.right = 0;
    r2.left = r2.right = 0;
 
    pitch -= kd->lowKey;
    if(pitch < 0 || pitch >= kd->keyCount)
        goto goHome;
 
    octave = pitch / 12;
    pitch = pitch % 12;
 
    blackKey = false;
 
    if(pitch == 1 || pitch == 3
            || pitch == 6 || pitch == 8 || pitch == 10)
        {
        /*
         * Black Keys
         */
        blackKey = true;
        r1.left = kd->r.left + (*kd->keyRight)[pitch - 1] + 2;
        r1.top = kd->r.top + 3;
        r1.right = kd->r.left + (*kd->keyRight)[pitch];
        r1.bottom = kd->r.top + kBlackKeyBottom;
        }
    else
        {
        /*
         * White Keys
         */
        k = kd->r.left + 2;
        i = 0;
        while((*kd->whiteKey)[i] != pitch)
            {
            i++;
            k += 9;
            }
        r1.left = k;
        r1.top = kd->r.top + kBlackKeyBottom + 2;
        r1.right = k+6;
        r1.bottom = kd->r.bottom - 1;
 
        if(pitch)
            r2.left = kd->r.left + (*kd->keyRight)[pitch - 1] + 2;
        else
            r2.left = kd->r.left + 2;
        r2.top = kd->r.top + 2;
        r2.right = kd->r.left + (*kd->keyRight)[pitch];
        r2.bottom = kd->r.top + kBlackKeyBottom + 2;
 
        /*
         * This is cheesy and proves I have
         * no idea what I am doing. - dvb
         */
        if(pitch == 5)
            r2.left ++;
        else if(pitch == 11)
            r2.right --;
        }
 
    OffsetRect(&r1,octave * 63,0);
    OffsetRect(&r2,octave * 63,0);
 
    if(gray >=0)
        {
        RGBColor c;
 
        if(!blackKey)
            gray = 255 - gray;
        c.blue = c.green = c.red = (((unsigned short)gray)<<8) | gray;
        RGBForeColor(&c);
        }
 
    if(gray == -1)
        {
        InvertRect(&r1);
        InvertRect(&r2);
        }
    else
        {
        PaintRect(&r1);
        PaintRect(&r2);
        }
goHome:
    ForeColor(blackColor);
    PenNormal();
    }
 
 
void PaintKeyboardVector(KeyboardDiagram *kd,unsigned char *keyVel)
    {
    short i;
    unsigned char *w1,*w2;
    long x;
 
    w1 = keyVel;
    w2 = kd->keyVel;
    for(i = 0; i < 128; i++)
        {
        x = *w1;
        if(*w2 != x)
            {
            *w2 = x;
            x = x ? x+128:0;
            if( (i < kd->lowKey) || (i >= (kd->lowKey + kd->keyCount)) )
                {
                if(kd->mod)
                    PaintKeyboardKey(kd,
                            (i+kd->modOffset)%(kd->keyCount)+kd->lowKey,x);
                }
            PaintKeyboardKey(kd,i,x);
            }
        w1++;
        w2++;
        }
    }
 
 
short GetKeyboardKey(KeyboardDiagram *kd,Point p)
/*
 * Return -1 if outside rectangle.
 */
    {
    short pitch,octave;
 
    if(PtInRect(p,&kd->r))
        {
        p.h -= kd->r.left;
        p.v -= kd->r.top;
 
        octave = p.h / 63;
        p.h %= 63;
 
        if(p.v > kBlackKeyBottom)
            pitch = (*kd->whiteKey)[p.h/9];
        else
            {
            pitch = 0;
            while((*kd->keyRight)[pitch] < p.h)
                pitch++;
            }
        pitch += octave*12;
        pitch += kd->lowKey;
        }
    else
        pitch = -1;
 
    return pitch;
    }