/*
 * $Id: envelope.cxx,v 1.2 1996/02/16 01:02:01 ms Exp $
 *
 *
 * $Log: envelope.cxx,v $
 * Revision 1.2  1996/02/16 01:02:01  ms
 * *** empty log message ***
 *
 * Revision 1.1  1996/01/27 01:41:40  ms
 * moved initialization of AmplModTable to init.c
 *
 * Revision 1.0  1996/01/21 04:12:05  ms
 * Initial revision
 *
 */

#include "mytypes.h"
#include "opstruct.h"
#include "enve_ac.h"
#include "enve_dc.h"

#define envelopelaenge 2400


ubyte Mvol[16] =
{
  0,23,41,57,77,96,114,132,
  155,173,187,200,216,228,241,255
};

uword Atime[16] =
{
  2,8,16,24,38,56,68,80,
  100,250,500,800,1000,3000,5000,8000
};

uword DRtime[16] =
{
  8,24,48,72,114,168,204,240,
  300,750,1500,2400,3000,9000,15000,24000
};

uword Arate[2*16];
uword DRrate[2*16];  

uword attackpos[256];
uword releasepos[256];                  

ubyte MasterVolume;

ubyte MAmplModTable[16*256];            


void enveemuinit( udword pcmfreq )
{
  int i, j, k;
  udword zwi;
  
  for ( i = 0; i < 256; i++ )
  {
    j = 0;
    while ( (j < envelopelaenge) && (attacktab[j] != i) )  j++;
    attackpos[i]=j;
  }

  for ( i = 0; i < 256; i++ )
  {
    j = 0;
    while ( (j < envelopelaenge) && (releasetab[j] !=i) )  j++;
    releasepos[i]=j;
  }

  k = 0;
  for ( i = 0; i < 16; i++ )
  {
    for ( j = 0; j < 256; j++ )  MAmplModTable[k++] = ( j * Mvol[i] ) / 255;
  }

  for ( i = 0; i < 16; i++ )
  {
    zwi = ( Atime[i] * pcmfreq ) / 1000;
    Arate[2*i] = envelopelaenge / zwi;
    Arate[(2*i)+1] = (( envelopelaenge % zwi ) * 65536 ) / zwi;

    zwi = ( DRtime[i] * pcmfreq ) / 1000;
    DRrate[2*i] = envelopelaenge / zwi;
    DRrate[(2*i)+1] = (( envelopelaenge % zwi ) * 65536 ) / zwi;
  }
}


inline ubyte SID_mute(struct sidoperator*);
inline ubyte SID_attack(struct sidoperator*);
inline ubyte SID_decay(struct sidoperator*);
inline ubyte SID_sustain(struct sidoperator*);
inline ubyte SID_release(struct sidoperator*);
inline ubyte SID_startattack(struct sidoperator*);
inline ubyte SID_startdecay(struct sidoperator*);
inline ubyte SID_startsustain(struct sidoperator *);
inline ubyte SID_startrelease(struct sidoperator*);
inline ubyte SID_alterattack(struct sidoperator*);
inline ubyte SID_alterdecay(struct sidoperator*);
inline ubyte SID_altersustain(struct sidoperator*);
inline ubyte SID_alterrelease(struct sidoperator*);


ptr2sidfunc EnveModeTable[] =
{
  &SID_startattack, &SID_startrelease,
  &SID_attack, &SID_decay, &SID_sustain, &SID_release,
  &SID_mute, &SID_mute,

  &SID_startattack, &SID_startrelease,
  &SID_alterattack, &SID_alterdecay, &SID_altersustain, &SID_alterrelease,
  &SID_mute, &SID_mute
};


inline void SID_enveadvance(struct sidoperator* pvoice)
{
  register udword temp = (udword)pvoice->ENVADDPNT
  		       + (udword)pvoice->ENVPNT;
  pvoice->ENVADDPNT = temp & 0xFFFF;
  pvoice->ENVADDSTEP += pvoice->ENVSTEP + ( temp > 65535 );
}


inline ubyte SID_startattack(struct sidoperator* pvoice)
{
  pvoice->ADSRCTRL = 4;
  pvoice->ENVADDSTEP = attackpos[pvoice->ENVVOL];
  return(SID_alterattack(pvoice));
}

inline ubyte SID_alterattack(struct sidoperator* pvoice)
{
  register ubyte attack = pvoice->SIDAD >> 4;
  pvoice->ENVSTEP = Arate[attack *2];
  pvoice->ENVPNT = Arate[(attack *2) +1];
  pvoice->ADSRSUB = &SID_attack;
  return(SID_attack(pvoice));
}

inline ubyte SID_attack(struct sidoperator* pvoice)
{
  if ( pvoice->ENVADDSTEP >= envelopelaenge )  return(SID_startdecay(pvoice));
  else
  {
    pvoice->ENVVOL = attacktab[pvoice->ENVADDSTEP];
    SID_enveadvance(pvoice);
    return(MAmplModTable[( MasterVolume << 8 ) + pvoice->ENVVOL ]);
  }
}

inline ubyte SID_startdecay(struct sidoperator* pvoice)
{
  pvoice->ADSRCTRL = 6;
  pvoice->ENVADDSTEP = 0;
  return(SID_alterdecay(pvoice));
}

inline ubyte SID_alterdecay(struct sidoperator* pvoice)
{
  register ubyte decay = pvoice->SIDAD & 0x0F ;
  pvoice->ENVSTEP = DRrate[decay *2];
  pvoice->ENVPNT = DRrate[(decay *2) +1];
  pvoice->ADSRSUB = &SID_decay;
  return(SID_decay(pvoice));
}

inline ubyte SID_decay(struct sidoperator* pvoice)
{
  if ( pvoice->ENVADDSTEP >= envelopelaenge )  return(SID_sustain(pvoice));
  else
  {
    pvoice->ENVVOL = releasetab[pvoice->ENVADDSTEP];
    if ( pvoice->ENVVOL <= pvoice->ENVSUSVOL )  return(SID_startsustain(pvoice));
    SID_enveadvance(pvoice);
    return(MAmplModTable[( MasterVolume << 8 ) + pvoice->ENVVOL ]);
  }
}

inline ubyte SID_startsustain(struct sidoperator* pvoice)
{
  pvoice->ADSRCTRL = 8;
  return(SID_altersustain(pvoice));
}

inline ubyte SID_altersustain(struct sidoperator* pvoice)
{
  pvoice->ADSRSUB = &SID_sustain;
  pvoice->ENVVOL = pvoice->ENVSUSVOL;
  return(SID_sustain(pvoice));
}

inline ubyte SID_sustain(struct sidoperator* pvoice)
{
  return(MAmplModTable[( MasterVolume << 8 ) + pvoice->ENVVOL ]);
}

inline ubyte SID_startrelease(struct sidoperator* pvoice)
{
  pvoice->ADSRCTRL = 10;
  pvoice->ENVADDSTEP = releasepos[pvoice->ENVVOL];
  return(SID_alterrelease(pvoice));
}

inline ubyte SID_alterrelease(struct sidoperator* pvoice)
{
  register ubyte release = pvoice->SIDSR & 0x0F;
  pvoice->ENVSTEP = DRrate[release *2];
  pvoice->ENVPNT = DRrate[(release *2) +1];
  pvoice->ADSRSUB = &SID_release;
  return(SID_release(pvoice));
}

inline ubyte SID_release(struct sidoperator* pvoice)
{
  if ( pvoice->ENVADDSTEP >= envelopelaenge )  return(SID_mute(pvoice));
  else
  {
    pvoice->ENVVOL = releasetab[pvoice->ENVADDSTEP];
    SID_enveadvance(pvoice);
    return(MAmplModTable[( MasterVolume << 8 ) + pvoice->ENVVOL ]);
  }
}

inline ubyte SID_mute(struct sidoperator* pvoice)
{
  pvoice->ADSRSUB = &SID_mute;
  return( pvoice->ENVVOL = 0 );
}
