/*****************************************************************************/
/*                                                                           */
/*   VECTREX HP3000 Software Emulator              Copyright K.Wilkins 1996  */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*   Title      : AY-3-8192 Sound Chip emulation module                      */
/*                                                                           */
/*   File Name  : SOUNDEMU.C                                                 */
/*                                                                           */
/*   Author     : C.S.                                                       */
/*                                                                           */
/*   Version    : 1.00                                                       */
/*                                                                           */
/*   Desciption : This file contains the functions that emulate the AY-3-8192*/
/*                Chip. Any emulation functions calling the read write       */
/*                functions will cause an immediate update to the chip and   */
/*                and all associated variables.                              */
/*                                                                           */
/*   Functions  : fSoundInit()      - Init the AY-3-8192 Sound chip          */
/*                fSoundTick()      - Emulate one time tick of the chip      */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*   Revision History:                                                       */
/*                                                                           */
/*   Version    Date    Who  Description of changes                          */
/*   -------    ----    ---  ----------------------                          */
/*                                                                           */
/*    0.01    14/03/93  K.W  Creation of empty file and descriptions         */
/*    1.00    05/08/96  K.W  Public release of DVE V1.0                      */
/*                                                                           */
/*****************************************************************************/
/*
** $Id:$
**
** File: psg.c -- software implementation of AY-3-8910 Programmable
**              sound generator.
**
** Based on: Sound.c, (C) Ville Hallik (ville@physic.ut.ee) 1996
**
** SCC emulation removed.  Made modular and capable of multiple PSG
** emulation.
**
** Modifications (C) 1996 Michael Cuddy, Fen's Ende Software.
** http://www.fensende.com/Users/mcuddy
**
*/

/*
** Initialize AY8910 emulator(s).
**
** 'num' is the number of virtual AY8910's to allocate
** 'rate' is sampling rate and 'bufsiz' is the size of the
** buffer that should be updated at each interval
*/

#ifdef _NO_DEBUG_INFORMATION_


#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <stdarg.h>
#include <mem.h>
#include <stdlib.h>

#include <audio.h>

#include <standard.h>
#include <tools.h>

#include "vdebug.h"
#include "vectrex.h"
#include "emu6809.h"
#include "emu6522.h"
#include "joystick.h"
#include "keyboard.h"
#include "verror.h"
#include "psg.h"
#include "sound.h"
#include "sealsnd.h"
#include "sequence.h"



/*
** some globals ...
*/

static SAMPLE *Buf;           /* sound buffer */
static T_INT UserBuffer;      /* if user provided buffers */
static AYPortHandler Port[2]; /* 'A' and 'B' port */

static T_INT seal_is_init=0;
static T_INT Incr0, Incr1, Incr2;
static T_INT Increnv, Incrnoise;
static T_INT StateNoise, NoiseGen;
static T_INT Counter0, Counter1, Counter2, Countenv, Countnoise;
static T_INT Vol0, Vol1, Vol2, Volnoise, Envelope;

static T_INT AYSoundRate;         /* Output rate (Hz) */
static T_INT AYBufSize;           /* size of sound buffer, in samples */

static T_INT sample_pos=0;
static T_INT sample_counter=0;
static T_INT sample_mul=4;

static T_UCHAR _AYEnvForms[16][32] = {
        { 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
        { 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
        { 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
        { 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
        {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
        {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
        {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
        {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
        { 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,
          15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0 },
        { 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
        { 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,
           0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 },
        { 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,
          15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 },
        {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
           0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 },
        {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
          15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 },
        {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
          15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0 },
        {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }
};

#define SAMPLE_RATE 22050

AUDIOINFO info;
AUDIOCAPS caps;
HAC hVoice;
LPAUDIOWAVE lpWave=NULL;
T_BYTE Regs[18];

volatile long dwTimerAccum = 0L;
static T_INT seal_timer=0;
static T_INT update_len=0;

T_VOID interrupt far TimerHandler(T_VOID)
{
 T_INT i, x;
 T_INT c0, c1, l0, l1, l2;
 // if a sample was played, than ONLY the sample is on output!
 // this is true for all vectrex stuff, if otherwise needed,
 // remove the else from sample_pos
 // and or the stuff to Buf[]
 if (sample_pos>10) // spike playes a one byte 0 sample all through the game...
 {
  // the following is a weak attempt to
  // synchronize to the sample rate...
  // handled by buffer size instead of
  // AYSoundRate
  static T_INT last_pos=80;
  if (sample_pos<AYBufSize)
  {
   if (abs(last_pos-sample_pos)<15)
    sample_mul=(AYBufSize+(sample_pos-(sample_pos>>2)))/sample_pos;
  }
  last_pos=sample_pos;
  for (i=sample_counter;i<AYBufSize;i++)
    Buf[i] = Buf[sample_counter-1];
  sample_counter=0;
  sample_pos=0;
 }
 else
 {
  x = ( Regs[AY_AFINE]+((unsigned)( Regs[AY_ACOARSE]&0xF)<<8));
   Incr0 = x ? AY8910_CLOCK / AYSoundRate * 4 / x : 0;

  x = ( Regs[AY_BFINE]+((unsigned)( Regs[AY_BCOARSE]&0xF)<<8));
   Incr1 = x ? AY8910_CLOCK / AYSoundRate * 4 / x : 0;

  x = ( Regs[AY_CFINE]+((unsigned)( Regs[AY_CCOARSE]&0xF)<<8));
   Incr2 = x ? AY8910_CLOCK / AYSoundRate * 4 / x : 0;

  x =  Regs[AY_NOISEPER]&0x1F;
   Incrnoise = AY8910_CLOCK / AYSoundRate * 4 / ( x ? x : 1 );

  x = ( Regs[AY_EFINE]+((unsigned) Regs[AY_ECOARSE]<<8));
   Increnv = x ? AY8910_CLOCK / AYSoundRate * 4 / x * AYBufSize : 0;

  Envelope = _AYEnvForms[ Regs[AY_ESHAPE]][( Countenv>>16)&0x1F];

  if ( (  Countenv +=  Increnv ) & 0xFFE00000 )
  {
   switch(  Regs[AY_ESHAPE] )
   {
    case 8:
    case 10:
    case 12:
    case 14:
      Countenv -= 0x200000;
     break;
    default:
      Countenv = 0x100000;
      Increnv = 0;
   }
  }
  Vol0 = (  Regs[AY_AVOL] < 16 ) ?  Regs[AY_AVOL] :  Envelope;
  Vol1 = (  Regs[AY_BVOL] < 16 ) ?  Regs[AY_BVOL] :  Envelope;
  Vol2 = (  Regs[AY_CVOL] < 16 ) ?  Regs[AY_CVOL] :  Envelope;

  Volnoise = (
      ( (  Regs[AY_ENABLE] & 010 ) ? 0 :  Vol0 ) +
      ( (  Regs[AY_ENABLE] & 020 ) ? 0 :  Vol1 ) +
      ( (  Regs[AY_ENABLE] & 040 ) ? 0 :  Vol2 ) ) / 2;

  Vol0 = (  Regs[AY_ENABLE] & 001 ) ? 0 :  Vol0;
  Vol1 = (  Regs[AY_ENABLE] & 002 ) ? 0 :  Vol1;
  Vol2 = (  Regs[AY_ENABLE] & 004 ) ? 0 :  Vol2;

  for ( i=0; i<AYBufSize; ++i )
  {
   /*
   ** These strange tricks are needed for getting rid
   ** of nasty interferences between sampling frequency
   ** and "rectangular sound" (which is also the output
   ** of real AY-3-8910) we produce.
   */

   c0 =  Counter0;
   c1 =  Counter0 +  Incr0;
   l0 = ((c0&0x8000)?-16:16);
   if ( (c0^c1)&0x8000 )
   {
    l0=l0*(0x8000-(c0&0x7FFF)-(c1&0x7FFF))/ Incr0;
   }
   Counter0 = c1 & 0xFFFF;

   c0 =  Counter1;
   c1 =  Counter1 +  Incr1;
   l1 = ((c0&0x8000)?-16:16);
   if ( (c0^c1)&0x8000 )
   {
    l1=l1*(0x8000-(c0&0x7FFF)-(c1&0x7FFF))/ Incr1;
   }
    Counter1 = c1 & 0xFFFF;

   c0 =  Counter2;
   c1 =  Counter2 +  Incr2;
   l2 = ((c0&0x8000)?-16:16);
   if ( (c0^c1)&0x8000 )
   {
    l2=l2*(0x8000-(c0&0x7FFF)-(c1&0x7FFF))/ Incr2;
   }
    Counter2 = c1 & 0xFFFF;

    Countnoise &= 0xFFFF;
   if ( (  Countnoise +=  Incrnoise ) & 0xFFFF0000 )
   {
    /*
    ** The following code is a random bit generator :)
    */
     StateNoise =
        ( (  NoiseGen <<= 1 ) & 0x80000000
        ?  NoiseGen ^= 0x00040001 :  NoiseGen ) & 1;
   }

    Buf[i] = AUDIO_CONV (
       ( l0 *  Vol0 + l1 *  Vol1 + l2 *  Vol2 ) / 6 +
       (  StateNoise ?  Volnoise : - Volnoise ) );
  }
 }
 // upload the data to the audio DRAM local memory
 AWriteAudioData(lpWave,0,update_len);
 APlayVoice(hVoice,lpWave);
 AUpdateAudio();
 timer_tick++;
// if ((dwTimerAccum += TIMER_RATE) >= 0x10000L)
// {
//  dwTimerAccum -= 0x10000L;
//  timer_tick++;
//  dos_timer_handler();
//  lpfnBIOSTimerHandler();
// }
}

T_INT AYInit(T_INT rate, T_INT bufsiz, SAMPLE *buf)
{
 AYSoundRate = rate;
 AYBufSize = bufsiz;
 UserBuffer = 0;
 Buf=buf;
 Port[0] = Port[1] = NULL;
 AYResetChip();
 return 0;
}

T_VOID AYShutdown(T_VOID)
{
 AYSoundRate = AYBufSize = 0;
}

/*
** reset all chip registers.
*/
T_VOID AYResetChip(T_VOID)
{
 T_INT i;
 memset(Buf,'\0',AYBufSize);

 /* initialize hardware registers */
 for( i=0; i<16; i++ )
  Regs[i] = AUDIO_CONV(0);

 Regs[AY_ENABLE] = 077;
 Regs[AY_AVOL] = 8;
 Regs[AY_BVOL] = 8;
 Regs[AY_CVOL] = 8;
 NoiseGen = 1;
 Envelope = 15;
 StateNoise = 0;
 Incr0= Incr1 = Incr2 = Increnv = Incrnoise = 0;
}
/*
** set a port handler function to be called when AYWriteReg() or AYReadReg()
** is called for register AY_PORTA or AY_PORTB.
*/
T_VOID AYSetPortHandler(T_INT port, AYPortHandler func)
{
 port -= AY_PORTA;
 if (port > 1 || port < 0 )
  return;
  Port[port] = func;
}

T_VOID sealinfo(T_VOID)
{
 if (AInitialize()!=0)
 {
 t_printf(E_VERBOSE_NONE,"\nSEAL Sound nicht initialisiert!");
 }
 else
 {
  for (info.nDeviceId = 0; info.nDeviceId < AGetAudioNumDevs(); info.nDeviceId++)
  {
   AGetAudioDevCaps(info.nDeviceId, &caps);
   t_printf(E_VERBOSE_NONE,"nDeviceId=%d wProductId=%d szProductName=%s\n", info.nDeviceId, caps.wProductId, caps.szProductName);
  }
 }
}

#endif //#ifdef _NO_DEBUG_INFORMATION_

#ifndef _NO_DEBUG_INFORMATION_

T_VOID sealInitTimerHandler(T_VOID)
{
 if (seal_timer==0)
 {
  seal_timer=1;
  dos_timer_handler = _dos_getvect(DOS_TIMER_IRQ);
  _dos_setvect(DOS_TIMER_IRQ, TimerHandler);
  outp(0x43, 0x34);
  outp(0x40, LOBYTE(TIMER_RATE));
  outp(0x40, HIBYTE(TIMER_RATE));
 }
}

T_VOID sealDoneTimerHandler(T_VOID)
{
 if (seal_timer==1)
 {
  seal_timer=0;
  outp(0x43, 0x34);
  outp(0x40, 0x00);
  outp(0x40, 0x00);
  _dos_setvect(DOS_TIMER_IRQ, dos_timer_handler);
 }
}

BOOL fsealSoundInit(T_VOID)
{
 if (AInitialize()!=0)
 {
 t_printf(E_VERBOSE_NONE,"\nSEAL Sound nicht initialisiert!");
  exit(1);
 }
 else
 {
  seal_is_init=1;
  info.nDeviceId = wGblseal_audio_device;
  info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO;
#ifdef USEFILTER
    /* enable antialias dynamic filtering */
    info.wFormat |= AUDIO_FORMAT_FILTER;
#endif
  info.nSampleRate = SAMPLE_RATE;
  if (AOpenAudio(&info) != AUDIO_ERROR_NONE)
  {
  t_printf(E_VERBOSE_NONE,"Audio initialization failed (SEAL).\n");
   exit(1);
  }
  else
  {
   if (bGblDisplayVerbose==T_TRUE)
   {
   t_printf(E_VERBOSE_NONE,"Audio device initialized at %d bits %s %u Hz\n",
            info.wFormat & AUDIO_FORMAT_16BITS ? 16 : 8,
            info.wFormat & AUDIO_FORMAT_STEREO ?
            "stereo" : "mono", info.nSampleRate);
    /* show device information */
    AGetAudioDevCaps(info.nDeviceId, &caps);
   t_printf(E_VERBOSE_NONE,"%s detected. \n", caps.szProductName);
   }
  }
 }
 /* open and allocate voices, allocate waveforms */
 if (AOpenVoices(1) != AUDIO_ERROR_NONE)
 {
 t_printf(E_VERBOSE_NONE,"voices initialization failed (SEAL).\n");
  return T_FALSE;
 }
 if (ACreateAudioVoice(&hVoice) != AUDIO_ERROR_NONE)
 {
 t_printf(E_VERBOSE_NONE,"voice creation failed (SEAL).\n");
  return T_FALSE;
 }
 ASetVoicePanning(hVoice,128);
 if ((lpWave = (LPAUDIOWAVE) malloc(sizeof(AUDIOWAVE))) == 0)
  return T_FALSE;
 update_len=info.nSampleRate/UPDATES_PER_SEC;
 lpWave->wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO;
 lpWave->nSampleRate = info.nSampleRate;
 lpWave->dwLength = update_len;
 lpWave->dwLoopStart = lpWave->dwLoopEnd = 0;

 if (ACreateAudioData(lpWave) != AUDIO_ERROR_NONE)
 {
  free(lpWave);
  return T_FALSE;
 }
 AYInit(info.nSampleRate, update_len, lpWave->lpData);
 ASetVoiceVolume(hVoice,64);
 fSoundReset();
 if (bGblDisplayVerbose==T_TRUE)
 t_printf(E_VERBOSE_NONE,"\nSEAL and PSG Sound init OK!");
 return(T_TRUE);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fSoundReset()                                             */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Do a hardware reset of the sound chip                     */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_VOID fsealSoundReset(T_VOID)
{
 AYResetChip();
 return;
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fSoundRestore()                                           */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Shutdown the sound chip before exit.                      */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_VOID fsealSoundRestore(T_VOID)
{
 if (seal_is_init==0)
  return;
 seal_is_init=0;
 AStopVoice(hVoice);
 ADestroyAudioVoice(hVoice);
 ADestroyAudioData(lpWave);
 if (lpWave!=NULL)
 {
  free(lpWave);
  lpWave=NULL;
 }
 AYShutdown();
 ACloseVoices();
 ACloseAudio();
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : fSoundTick()                                              */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Do one unit of sound chip emulation.                      */
/*                                                                           */
/*   Accepts     : nothing                                                   */
/*                                                                           */
/*   Returns     : nothing                                                   */
/*                                                                           */
/*****************************************************************************/

T_VOID fsealSoundTick(T_VOID)
{
 T_UCHAR tTmp;
 if ((digisound==T_TRUE)&&((tOLD_BDIR|tOLD_BC1)==0))
 {
  T_INT i;
  T_UCHAR tData=(T_UCHAR)((((T_SCHAR)(t6522ORA))+(T_SCHAR)(128)));
  tData=t6522ORA;
  // ****************************************
  //  Use ... for speed regulator checking  *
  // ****************************************
  if (lwGblSystemTickTotal>tick_timeout)
  {
#ifndef DEBUG_MSG
   if (!tTicker--)
   {
    tTicker=KBD_WAIT;
    if (KBDKeyPressed)
    {
     fKBDdokey();
    }
   }
#endif
   while (last_timer_tick==timer_tick)
   {
    // ****************************************************
    // * Pause until timer rollover, check for timeout ?? *
    // ****************************************************
    ;
   }
   last_timer_tick=timer_tick;
   tick_timeout=lwGblSystemTickTotal+lwGblMaxTicks;
  }
  if (last_was_digi_sound==T_FALSE)
  {
   last_was_digi_sound=T_TRUE;
  }
  for (i=0;i<sample_mul;i++)
   if (sample_counter<AYBufSize)
    Buf[sample_counter++] =tData;
  sample_pos++;
 }
 else if (tOLD_BC1!=tSIGDEF_AY3BC1 || tOLD_BDIR!=tSIGDEF_AY3BDIR)
 {
  tTmp=tOLD_BDIR|tOLD_BC1;
  fDebug(MED,("fSoundTick() - %02x",tTmp));
  if (last_was_digi_sound==T_TRUE)
  {
   last_was_digi_sound=T_FALSE;
  }
  switch(tTmp)
  {
   case 0x00:   // Back to the inactive state
   {
    break;
   }
   case 0x08:   // Read from AY-3-8192
   {
    switch(tAddr)
    {
     case 0x0e:
     {
      // Build the key T_BYTE
      tKeyWord =(fKBDisdown(wGblPly2Button4))?0:1<<7;
      tKeyWord|=(fKBDisdown(wGblPly2Button3))?0:1<<6;
      tKeyWord|=(fKBDisdown(wGblPly2Button2))?0:1<<5;
      tKeyWord|=(fKBDisdown(wGblPly2Button1))?0:1<<4;
      tKeyWord|=(fKBDisdown(wGblPly1Button4))?0:1<<3;
      tKeyWord|=(fKBDisdown(wGblPly1Button3))?0:1<<2;
      tKeyWord|=(fKBDisdown(wGblPly1Button2))?0:1<<1;
      tKeyWord|=(fKBDisdown(wGblPly1Button1))?0:1<<0;

      if (wGblPCJoystick)
      {
       if (button1a)
        tKeyWord&=255-0x08;
       if (button1b)
        tKeyWord&=255-0x04;
       if (button2a)
        tKeyWord&=255-0x80;
       if (button2b)
        tKeyWord&=255-0x40;
      }
      if (!tKeyWord&0x80)
      {
       t6522CA1=1; // muesste hier gesetzt werden und im 6522 abgefragt werden!
       t6522IFLG|=E6522IFLG_CA1;
//       t6522AUX_PA_LE=1;
       if (t6522IER&E6522IFLG_CA1)
        tsCPURegisters.tIRQFlag=T_TRUE; /* CA1 -> keyboard 2 normaler IRQ ??? */
      }
      else
      {
       t6522CA1=0;
       t6522IFLG&=(255-E6522IFLG_CA1);
//       t6522AUX_PA_LE=0;
      }
      if (!tKeyWord&0x08)
      {
       tsCPURegisters.tFIRQFlag=T_TRUE;
      }
      fDebug(MED,("fSoundTick() - Joypad button returned %02x",tKeyWord));
      t6522IRA=tKeyWord;
      break;
     }
     default:
     {
      fDebug(MED,("fSoundTick() - Bad register select"));
     }
     break;
    }
    break;
   }
   case 0x10:   // Write to AY-3-8192
   {
    {
     Regs[tAddr] = t6522ORA;
     switch (tAddr)
     {
      case AY_AVOL:
      case AY_BVOL:
      case AY_CVOL:
      {
       Regs[tAddr] &= 0x1F;       /* mask volume */
       break;
       }
      case AY_EFINE:
      case AY_ECOARSE:
      {
       Countenv=0;
       /* fall through */
      }
      case AY_ESHAPE:
      {
       Regs[AY_ESHAPE] &= 0xF;
       break;
      }
      case AY_PORTA: // only needed for goggle support ?
      {
       static T_ULONG last=0;
       if ((tKeyOut&(255-128)))
       {
        if (t6522ORA!=255)
        {
         imager_pulse_ticks=lwGblSystemTickTotal-last;
        }
       }
       last=lwGblSystemTickTotal;
       tKeyOut=t6522ORA;

/*
       // is not neccessary, since the port is only needed for imager
       if (Port[0])
       {
        (Port[0])(AY_PORTA,1,t6522ORA);
       }
*/
       break;
      }
      case AY_PORTB: // not available on 8912
      {
/*
       if (Port[1])
       {
        (Port[1])(AY_PORTB,1,t6522ORA);
       }
*/
       break;
      }
     }
    } // else if (digisound==T_TRUE)
    break;
   }
   case 0x18:   // Latch address to AY-3-8192
   {
    fDebug(MED,("fSoundTick() - Latch Address"));
    tAddr=t6522ORA&0x0f;
    break;
   }
   default:
   {
    break;
   }
  }
  tOLD_BC1=tSIGDEF_AY3BC1;
  tOLD_BDIR=tSIGDEF_AY3BDIR;
 } // if (tOLD_BC1!=tSIGDEF_AY3BC1 || tOLD_BDIR!=tSIGDEF_AY3BDIR)
}

T_VOID fsealSoundMute(T_VOID)
{
}

T_VOID fsealSoundResume(T_VOID)
{
}

#endif //#ifndef _NO_DEBUG_INFORMATION_
