instrument.c++ 7.56 KB
//====================================================================
// instrument.c++
//
// Copyright 1993, Silicon Graphics, Inc.
// All Rights Reserved.
//
// This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
// the contents of this file may not be disclosed to third parties, copied or
// duplicated in any form, in whole or in part, without the prior written
// permission of Silicon Graphics, Inc.
//
// RESTRICTED RIGHTS LEGEND:
// Use, duplication or disclosure by the Government is subject to restrictions
// as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
// and Computer Software clause at DFARS 252.227-7013, and/or in similar or
// successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
// rights reserved under the Copyright Laws of the United States.
//====================================================================

#include <stdlib.h>
#include <bstring.h>
#include "libbank.h"

int soundCompare(const void *one, const void *two)
{
    ICKeyMap *k1 = (*(ICSound **)one)->GetKeyMap();
    ICKeyMap *k2 = (*(ICSound **)two)->GetKeyMap();


    if ((k1->keyMin == k2->keyMin) && (k1->velocityMin == k2->velocityMin) &&
        (k1->keyMax == k2->keyMax) && (k1->velocityMax == k2->velocityMax))
    {
        return 0; // k1 = k2
    } 

    if ((k2->keyMin <= k1->keyMax) && (k2->velocityMax >= k1->velocityMin) &&
        (k1->keyMin <= k2->keyMax) && (k1->velocityMax >= k2->velocityMin))
    {
        fprintf(stderr,"error: keymaps %s and %s overlap.\n",
                k1->GetName(),
                k2->GetName());
        exit (-1); // overlapping keymaps
    }
    
    if ((k1->keyMax < k2->keyMin) ||
        ((k1->velocityMax < k2->velocityMin) &&
         (k1->keyMax == k2->keyMax) &&
         (k1->keyMin == k2->keyMin)))
    {
        return -1; // k1 < k2
    } else {
        return 1; // k1 > k2
    }
}

ICInst::ICInst()
{
    declclass   = ICINST;
    size        = sizeof(ALInstrument) - sizeof(ALSound *);
    
    volume      = AL_VOL_FULL;
    pan         = AL_PAN_CENTER; 
    priority    = AL_DEFAULT_PRIORITY;
    soundCount  = 0;
    inst        = 0;
    tremType    = 0;
    tremRate    = 0;
    tremDepth   = 0;
    tremDelay   = 0;
    vibType     = 0;
    vibRate     = 0;
    vibDepth    = 0;
    vibDelay    = 0;
    bendRange   = 200;  /* a whole step either way */
    sortSounds  = 1;
}

void ICInst::AddSound(ICSound *s, int /*dummy*/)
{
    FailIf(s->GetObjectClass() != ICSOUND, IC_TYPE_ERR);

    soundList.Append(s);
    size += sizeof(ALSound *);
    soundCount++;
}

void ICInst::SetPriority(char prior)
{
    FailIf(prior > AL_MAX_PRIORITY, IC_PARAMETER_ERR);
    priority = prior;
}

void ICInst::SetPan(int p)
{
    FailIf(((p < AL_PAN_LEFT) || (p > AL_PAN_RIGHT)), IC_PARAMETER_ERR);
    pan = p;
}

void ICInst::SetVol(int vol)
{
    FailIf( (vol < 0) || (vol > AL_VOL_FULL), IC_PARAMETER_ERR);
    volume = vol;
}

void ICInst::SetPitchBendRange(s16 range)
{
    FailIf(range < 0, IC_PARAMETER_ERR);
    bendRange = range;
}

#define MIN_TREM_VALUE      0
#define MAX_TREM_VALUE      255

void ICInst::SetTremType(int type)
{
    FailIf(((type < MIN_TREM_VALUE) || (type > MAX_TREM_VALUE)), IC_PARAMETER_ERR);
    tremType = type;
}

void ICInst::SetTremRate(int rate)
{
    FailIf(((rate < MIN_TREM_VALUE) || (rate > MAX_TREM_VALUE)), IC_PARAMETER_ERR);
    tremRate = rate;
}

void ICInst::SetTremDepth(int depth)
{
    FailIf(((depth < MIN_TREM_VALUE) || (depth > MAX_TREM_VALUE)), IC_PARAMETER_ERR);
    tremDepth = depth;
}

void ICInst::SetTremDelay(int delay)
{
    FailIf(((delay < MIN_TREM_VALUE) || (delay > MAX_TREM_VALUE)), IC_PARAMETER_ERR);
    tremDelay = delay;
}

#define MIN_VIB_VALUE      0
#define MAX_VIB_VALUE      255

void ICInst::SetVibType(int type)
{
    FailIf(((type < MIN_VIB_VALUE) || (type > MAX_VIB_VALUE)), IC_PARAMETER_ERR);
    vibType = type;
}

void ICInst::SetVibRate(int rate)
{
    FailIf(((rate < MIN_VIB_VALUE) || (rate > MAX_VIB_VALUE)), IC_PARAMETER_ERR);
    vibRate = rate;
}

void ICInst::SetVibDepth(int depth)
{
    FailIf(((depth < MIN_VIB_VALUE) || (depth > MAX_VIB_VALUE)), IC_PARAMETER_ERR);
    vibDepth = depth;
}

void ICInst::SetVibDelay(int delay)
{
    FailIf(((delay < MIN_VIB_VALUE) || (delay > MAX_VIB_VALUE)), IC_PARAMETER_ERR);
    vibDelay = delay;
}

void ICInst::Assemble()
{
    Node        *obj;
    int         j = 0;
    int         n;

    FailIfMsg(!declid, IC_INTERNAL_ERR, "undeclared instrument");

    char msg[256];
    FailIfMsg(!soundCount, IC_MISC_ERR,
              icErrStr(msg, declid->name,
                       " must have at least one sound\n"));

    size = Size();
    
    ALInstrument  *i = (ALInstrument *)calloc(1, size);
    FailIf(!i, IC_INTERNAL_ERR);

    i->pan              = pan;
    i->volume           = volume;
    i->soundCount       = soundCount;
    i->bendRange        = bendRange;
    i->priority         = priority;
    i->tremType         = tremType;
    i->tremRate         = tremRate;
    i->tremDepth        = tremDepth;
    i->tremDelay        = tremDelay;
    i->vibType          = vibType;
    i->vibRate          = vibRate;
    i->vibDepth         = vibDepth;
    i->vibDelay         = vibDelay;

    
    for (obj = soundList.head; obj != 0; obj = obj->next) {
            i->soundArray[j++] = (ALSound *)obj->data;
    }

    if (sortSounds)
        qsort(i->soundArray, i->soundCount, sizeof(i->soundArray[0]),
              soundCompare);

    for (n = 0; n < i->soundCount; n++) {
        i->soundArray[n] = (ALSound *)((ICSound *)i->soundArray[n])->GetObjectOffset();
    }
    
    inst = i;
    thing = inst;
}

void ICInst::ThinSounds(void)
{
    Node        *node;
    Node        *prev;
    ICSound     *obj;
    
    if(usedFlag) /* don't bother if not used */
    {
        node = soundList.head;
        prev = (Node *)&soundList.head;

        while(node != 0)
        {
            obj = (ICSound*)node->data;
            if(obj->GetUsedFlag())
            {
                prev = node;
                node = node->next;
            }
            else
            {
                soundCount--;
                node = soundList.Remove(node,prev);
            }
        }
    }
}
void ICInst::MarkUsed(char key)
{
    Node        *node;
    ICSound     *sound;
    ICKeyMap    *keys;
    
    if(!usedFlag)
        usedFlag = TRUE;
    
    for (node = soundList.head; node != 0; node = node->next)
    {
        sound = (ICSound*)node->data;
        keys = sound->GetKeyMap();

        if(keys->keyMin <= key && keys->keyMax >= key)
        {
            sound->MarkUsed();
            return;
        }
    }
    fprintf(stderr,"Instrument %s, key %d, no sound for this note\n", declid->name,key);
}

void ICInst::Prune() 
{
    Node *node;

    this->IncRefCount();
    
    for (node = soundList.head; node != 0; node = node->next) {
        ICSound *sound = (ICSound *)node->data;
        sound->Prune();
    }
    
}

void ICInst::Print()
{
    FailIfMsg(!declid, IC_INTERNAL_ERR, "undeclared instrument");
    
    printf("Instrument: %s\n", declid->name);

    ICObject::Print();
    printf("\tvolume:\t\t= %x\n", inst->volume);
    printf("\tpan:\t\t= %x\n", inst->pan);
    printf("\ttremeloType = %x\n",inst->tremType);
    printf("\ttremeloRate = %x\n",inst->tremRate);
    printf("\ttremeloDepth = %x\n",inst->tremDepth);
    printf("\ttremeloDelay = %x\n",inst->tremDelay);
    printf("\tsoundCount:\t= %x\n", inst->soundCount);

    int j;
    for (j = 0; j < inst->soundCount; j++) {
        printf("\tsound: \t\t= 0x%x\n", inst->soundArray[j]);
    }

    printf("\n");
    
}

void ICInst::SetSort(int doSort) 
{
    sortSounds = doSort;
}