/******************************************************************************
*
* Copyright (C) 2009-2017  Brian Berlin
* 
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************
*
* FILENAME: pokeysound.c
*
* DESCRIPTION:  This contains functions for emulating Pokey sound functions
*
* AUTHORS:  bberlin
*
* CHANGE LOG
*
*  VER     DATE     CHANGED BY   DESCRIPTION OF CHANGE
* ------  --------  ----------   ------------------------------------
* 0.6.3   12/04/09  bberlin      Creation
******************************************************************************/
#include "pokeysound.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define CPU_FREQ        1792080

#define CPU_CYCLE_CUTOFF (81<<8)     /* about 22050 Hz */
#define GTIA_VOL 16

#define CHAN_1 0
#define CHAN_2 1
#define CHAN_3 2
#define CHAN_4 3
#define MAX_CHAN 4

/*
 * AUDCTL Values
 */
#define CH3_CH4    0x08 
#define CH1_CH2    0x10 
#define CLK_64KHZ  0x00 
#define CLK_15KHZ  0x01 
#define CH3_179MHZ 0x20 
#define CH1_179MHZ 0x40 
#define CH1_FILTER 0x04 
#define CH2_FILTER 0x02 

/*
 * VOL bit values
 */
#define SET_VOL_CHAN1 0x01
#define SET_VOL_CHAN2 0x02
#define SET_VOL_CHAN3 0x04
#define SET_VOL_CHAN4 0x08
#define SET_VOL_GTIA  0x10

#define CLR_VOL_CHAN1 0xfe
#define CLR_VOL_CHAN2 0xfd
#define CLR_VOL_CHAN3 0xfb
#define CLR_VOL_CHAN4 0xf7
#define CLR_VOL_GTIA  0xef

#define MAX_PS_EVENTS 0x10000

extern unsigned int pokey_cpu_clock;
unsigned int last_clock;

ps_chip pokeyChip[MAXPOKEYS];

static int numPokeyChips;

static unsigned char poly4tbl[16];
static unsigned char poly5tbl[32];
static unsigned char poly9tbl[512];
static unsigned char poly17tbl[131072];
unsigned char *polytbls[4];

static ps_event psEvents[MAX_PS_EVENTS];
static unsigned short eventStoreIndex;
static unsigned short eventPopIndex;

static unsigned int pMask[4];
static unsigned int vol_silence;

int samples;

void pokey_sound_process_events ( unsigned int clk );
void pokey_sound_start_init ( int chip, unsigned int clk );
void pokey_sound_end_init ( int chip, unsigned int clk );
void pokey_sound_align_toggle ( int chip, ps_chan *p_chan, unsigned int clk );
void pokey_sound_stimer ( int chip, unsigned int clk );
unsigned int pokey_calc_raw_counter ( int chip, int chan, int counter);
int pokey_calc_precision_counter ( int chip, int chan, int value, int drive_clk );
void pokey_sound_update_disabled_channel ( int chip, int chan, unsigned int clk );

/*
 * Build up our poly v time arrays
 */
static void build_poly_tables(void)
{
    unsigned char c;
    int i;
    //int j, get_out;
    unsigned char poly4=0x5;
    unsigned char poly5=0x19;

    /* FIXME: Go back and figure this out for 9 and 17
     *   doesn't seem to be right, but we do start with 0
     */
    unsigned int poly17=0x843e;
    unsigned int poly9=0xc6;

    for(i=0; i<15; i++)
    {
        poly4tbl[i] = ~poly4 & 0x1;
        c = ((poly4>>2)&1) ^ ((poly4>>3)&1);
        poly4 = ((poly4<<1)&15) + c;
    }

    for(i = 0; i < 31; i++) {
        poly5tbl[i] = ~poly5 & 0x1; 
        c = ((poly5 >> 2) ^ (poly5 >> 4)) & 1;
        poly5 = ((poly5 << 1) & 31) + c;
    }

    for(i = 0; i < 131071; i++) {
        poly17tbl[i] = (unsigned char) poly17 & 0x1;
        c = ((poly17 >> 11) ^ (poly17 >> 16)) & 1;

        poly17 = ((poly17 << 1) & 131071) + c;
    }

    for(i = 0; i < 511; i++) {
        poly9tbl[i] = (unsigned char) poly9 & 0x1;
        c = ((poly9 >> 3) ^ (poly9 >> 8)) & 1;

        poly9 = ((poly9 << 1) & 511) + c;
    }
}

static void set_poly_mask(void)
{
    pMask[NO_SEL] = 0;
    pMask[POLY4_SEL] = 15;
    pMask[POLY17_SEL] = 131071;
    pMask[POLY9_SEL] = 511;
}

static void clear_poly_mask(void)
{
    pMask[0] = pMask[1] = pMask[2] = pMask[3] = 0;
}

/******************************************************************************
**  Function   :  pokey_sound_init
**                            
**  Objective  :  This function initializes pokey sound functions
**
**  Parameters :  sample_freq - the sample frequency in Hz
**                chips       - number of pokey chips
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_init ( int sample_freq, int chips ) {

    int i,j;

    numPokeyChips = chips;

    build_poly_tables();
    set_poly_mask();
    polytbls[0] = poly4tbl; /* poly4[0] is 0 */
    polytbls[1] = poly4tbl;
    polytbls[2] = poly17tbl;
    polytbls[3] = poly9tbl;

    eventStoreIndex = eventPopIndex = 0;
    for (i = 0; i < MAX_PS_EVENTS; ++i) {
        psEvents[i].type = INVALID;
    }

    for ( i = 0; i < numPokeyChips; ++i ) {

        for ( j = 0; j < 16; ++j ) {

            pokeyChip[i].reg[j] = 0;

        }

        pokey_sound_update_freq ( sample_freq, 0x80 );
        pokeyChip[i].lastClock = pokey_cpu_clock;
        pokeyChip[i].clockPolyStart[POLY4_SEL] = pokey_cpu_clock;
        pokeyChip[i].clockPoly5Start = pokey_cpu_clock;
        pokeyChip[i].clockPolyStart[POLY9_SEL] = pokey_cpu_clock;
        pokeyChip[i].clockPolyStart[POLY17_SEL] = pokey_cpu_clock;
        pokeyChip[i].clock114Time = pokey_cpu_clock + 77;
        pokeyChip[i].clock28Time = pokey_cpu_clock + 19;
        pokeyChip[i].volChanBits = 0;
        pokeyChip[i].inInit = 0;

        for ( j = 0; j < 4; ++j ) {

            pokeyChip[i].chan[j].chan = j;
            pokeyChip[i].chan[j].enabled = 0;
            pokeyChip[i].chan[j].baseClock = CLK_64KHZ;
            pokeyChip[i].chan[j].counter = 1 << 8;
            pokeyChip[i].chan[j].toggleClk = 1;
            pokeyChip[i].chan[j].volume = 0;
            pokeyChip[i].chan[j].volumeOnly = 0;

            pokeyChip[i].chan[j].polySel = 0;
            pokeyChip[i].chan[j].poly5En = 0;
            pokeyChip[i].chan[j].filterEn = 0;

            pokeyChip[i].chan[j].ffPoly5Out = 1; /* turn on poly5 flip flop */
            pokeyChip[i].chan[j].ffFilterOut = 1; /* set flip flop is default */ 

            pokeyChip[i].chan[j].lastEventTime = pokey_cpu_clock;

        } /* end for each channel */

        pokey_sound_stimer( i, pokey_cpu_clock );
        last_clock = 0;

    } /* end for each chip */

    samples = 0;

} /* end pokey_sound_init */

/******************************************************************************
**  Function   :  pokey_sound_update_freq
**                            
**  Objective  :  This function is called by the outside to update the sampling
**                freq.  Left shift by 8 to keep precision
**
**  Parameters :  sample_freq - the sample frequency in Hz
**                silence_vol - the volume value for silence to use
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_update_freq ( int sample_freq, int silence_vol ) {

    int i;
    unsigned int tmp;

    tmp = (CPU_FREQ<<8) / sample_freq;

    vol_silence = silence_vol;

    for ( i = 0; i < numPokeyChips; ++i ) {
        pokeyChip[i].sampleCounter = tmp;
        pokey_sound_volume_update ( i );
    }

} /* end pokey_sound_update_freq */

/******************************************************************************
**  Function   :  pokey_sound_shift_clock
**                            
**  Objective  :  This function is called when pokey cpu clock crosses 0.
**                We shift everything so lastClock is at 0 with no crossover
**                We then adjust so that all clocks are in the past and return
**                that adjust shift value
**
**  Parameters :  shift - clock cycles to shift by
**                                                
**  return     :  new_shift - additional shift value to use
**      
******************************************************************************/ 
int pokey_sound_shift_clock ( int shift ) {

    int i, j;
	unsigned int new_shift;

    /*
     * Get disabled channels lastEventTime updated to lastClock
     */
    for ( i = 0; i < numPokeyChips; ++i ) {
        for ( j = CHAN_1; j < MAX_CHAN; ++j ) {
            pokey_sound_update_disabled_channel ( i, j, pokeyChip[0].lastClock );
        }
    }

    /*
     * Figure out index at 0 (this is not actually clock time)
     */
    for ( i = 0; i < numPokeyChips; ++i ) {
        pokeyChip[i].clock114Time = (pokeyChip[0].lastClock - pokeyChip[i].clock114Time) % 114;
        pokeyChip[i].clock28Time = (pokeyChip[0].lastClock - pokeyChip[i].clock28Time) % 28;
        pokeyChip[i].clockPoly5Start = (pokeyChip[0].lastClock - pokeyChip[i].clockPoly5Start) % 31;
        pokeyChip[i].clockPolyStart[POLY17_SEL] = (pokeyChip[0].lastClock - pokeyChip[i].clockPolyStart[POLY17_SEL]) % 131071;
        pokeyChip[i].clockPolyStart[POLY9_SEL] = (pokeyChip[0].lastClock - pokeyChip[i].clockPolyStart[POLY9_SEL]) % 511;
        pokeyChip[i].clockPolyStart[POLY4_SEL] = (pokeyChip[0].lastClock - pokeyChip[i].clockPolyStart[POLY4_SEL]) % 15;
    }
    pokeyChip[0].lastClock = 0;

    /*
     * Now, figure out max index and shift our clock by that
     */
    new_shift = 0;
    for ( i = 0; i < numPokeyChips; ++i ) {

        if (pokeyChip[i].clockPoly5Start > new_shift) new_shift = pokeyChip[i].clockPoly5Start;
        if (pokeyChip[i].clockPolyStart[POLY4_SEL] > new_shift) new_shift = pokeyChip[i].clockPolyStart[POLY4_SEL];
        if (pokeyChip[i].clockPolyStart[POLY9_SEL] > new_shift) new_shift = pokeyChip[i].clockPolyStart[POLY9_SEL];
        if (pokeyChip[i].clockPolyStart[POLY17_SEL] > new_shift) new_shift = pokeyChip[i].clockPolyStart[POLY17_SEL];
        if (pokeyChip[i].clock114Time > new_shift) new_shift = pokeyChip[i].clock114Time;
        if (pokeyChip[i].clock28Time > new_shift) new_shift = pokeyChip[i].clock28Time;
    }

    pokeyChip[0].lastClock += new_shift;
    for ( i = 0; i < numPokeyChips; ++i ) {
        for ( j = CHAN_1; j < MAX_CHAN; ++j ) {
            pokeyChip[i].chan[j].toggleClk += new_shift;
            pokeyChip[i].chan[j].lastEventTime += new_shift;
        }
    }

    /*
     * Figure out acutal clock values (lastClock minus index at lastClock)
     */
    for ( i = 0; i < numPokeyChips; ++i ) {
        pokeyChip[i].clock114Time = pokeyChip[0].lastClock - pokeyChip[i].clock114Time;
        pokeyChip[i].clock28Time = pokeyChip[0].lastClock - pokeyChip[i].clock28Time;
        pokeyChip[i].clockPoly5Start = pokeyChip[0].lastClock - pokeyChip[i].clockPoly5Start;
        pokeyChip[i].clockPolyStart[POLY4_SEL] = pokeyChip[0].lastClock - pokeyChip[i].clockPolyStart[POLY4_SEL];
        pokeyChip[i].clockPolyStart[POLY9_SEL] = pokeyChip[0].lastClock - pokeyChip[i].clockPolyStart[POLY9_SEL];
        pokeyChip[i].clockPolyStart[POLY17_SEL] = pokeyChip[0].lastClock - pokeyChip[i].clockPolyStart[POLY17_SEL];
    }

    return new_shift;

} /* end pokey_sound_shift_clock */

/******************************************************************************
**  Function   :  pokey_sound_determine_poly
**                            
**  Objective  :  This function determines poly select values
**
**  Parameters :  chip - the sample frequency in Hz
**                chan - channel to check for
**                polySel - pointer to poly select
**                poly5En - pointer to poly 5 enable
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_determine_poly (int chip, int chan, int *polySel, int *poly5En) {

    unsigned char tmp_poly;

    tmp_poly = pokeyChip[chip].reg[(chan << 1) | (AUDC1_C)] >> 5; 

    *polySel = 0;
    *poly5En = !(tmp_poly & 0x4);

    if ((tmp_poly & 0x3) == 0x2) {
        *polySel = 0x1; /* 4bit */
    }
    else if ((tmp_poly & 0x5) == 0x5) {
        *polySel = 0x0; /* Pure Tone */
    }
    else if (tmp_poly != 1 && tmp_poly != 3) {
        if ( pokeyChip[chip].reg[AUDCTL_C] & 0x80 ) {
            *polySel = 0x3; /* 9bit */
        }
        else {
            *polySel = 0x2; /* 17bit */
        }
    }

} /* end pokey_sound_determine_poly */

/******************************************************************************
**  Function   :  pokey_sound_determine_timer
**                            
**  Objective  :  This function determines baseClock and counter for channel
**
**  Parameters :  chip - the sample frequency in Hz
**                chan - channel to check for
**                baseClock - pointer to poly select
**                counter - pointer to poly 5 enable
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_determine_timer (int chip, int chan, int *baseClock, int *counter) {

    unsigned int tmp_mult, tmp_val;

    if ( chan == CHAN_3 && (pokeyChip[chip].reg[AUDCTL_C] & CH3_179MHZ) )
        *baseClock = CH3_179MHZ;
    else if ( chan == CHAN_1 && (pokeyChip[chip].reg[AUDCTL_C] & CH1_179MHZ) )
        *baseClock = CH1_179MHZ;
    else if ( (chan == CHAN_2 && (pokeyChip[chip].reg[AUDCTL_C] & CH1_CH2)) )
        *baseClock = CH1_CH2;
    else if ( (chan == CHAN_4 && (pokeyChip[chip].reg[AUDCTL_C] & CH3_CH4)) )
        *baseClock = CH3_CH4;
    else if ( pokeyChip[chip].reg[AUDCTL_C] & CLK_15KHZ )
        *baseClock = CLK_15KHZ;
    else
        *baseClock = CLK_64KHZ;

    /*
     * Figure out counter values
     */
    if ( pokeyChip[chip].reg[AUDCTL_C] & CLK_15KHZ )
        tmp_mult = 114;
    else
        tmp_mult = 28;

    tmp_val = pokeyChip[chip].reg[(chan<<1) | (AUDF1_C)]; 

    switch ( *baseClock ) {
        case CH3_CH4:
            if ( pokeyChip[chip].reg[AUDCTL_C] & CH3_179MHZ )
                *counter = ((tmp_val<<8) + pokeyChip[chip].reg[AUDF3_C] + 7) << 8;
            else
                *counter = (((tmp_val<<8) + pokeyChip[chip].reg[AUDF3_C] + 1) * tmp_mult) << 8;
            break;
        case CH1_CH2:
            if ( pokeyChip[chip].reg[AUDCTL_C] & CH1_179MHZ )
                *counter = ((tmp_val<<8) + pokeyChip[chip].reg[AUDF1_C] + 7) << 8;
            else
                *counter = (((tmp_val<<8) + pokeyChip[chip].reg[AUDF1_C] + 1) * tmp_mult) << 8;
            break;
        case CH1_179MHZ:
        case CH3_179MHZ:
            *counter = (tmp_val + 4) << 8;
            break;
        default:
            *counter = ((tmp_val+1) * tmp_mult) << 8;
            break;
    }

} /* end pokey_sound_determine_timer */

/******************************************************************************
**  Function   :  pokey_sound_determine_filter
**                            
**  Objective  :  This function determines filter enable values
**
**  Parameters :  chip - the sample frequency in Hz
**                chan - channel to check for
**                filterEn - pointer to filter enable
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_determine_filter (int chip, int chan, int *filterEn) {

    *filterEn = 0;
    if ( chan == CHAN_1 && (pokeyChip[chip].reg[AUDCTL_C] & CH1_FILTER) ) {
        *filterEn = 1;
        //printf("High Pass 1: %d %d\n", tmp_event->chan, tmp_event->sampCount);
    }
    if ( chan == CHAN_2 && (pokeyChip[chip].reg[AUDCTL_C] & CH2_FILTER) ) {
        *filterEn = 1;
        //printf("High Pass 2: %d %d\n", tmp_event->chan, tmp_event->sampCount);
    }

} /* end pokey_sound_determine_filter */

/******************************************************************************
**  Function   :  pokey_sound_reg_update
**                            
**  Objective  :  This function updates counters and properties based on a 
**                register change.  Register values are saved.
**
**  Parameters :  sample_freq - the sample frequency in Hz
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_reg_update ( unsigned int addr, unsigned int val, int chip, 
                              int gain ) {

    int i;
    int chanChanged[4] = {0};
    ps_event *tmp_event;

    /*
     * Determine what register and channels need updating;
     */
    addr &= 0xf;
    switch ( addr ) {

        case AUDF1_C:
        case AUDF2_C:
        case AUDF3_C:
        case AUDF4_C:
            chanChanged[addr>>1] = 1;
            pokeyChip[chip].reg[addr] = val;
            if ( addr == AUDC1_C && (pokeyChip[chip].reg[AUDCTL_C] & 0x10) )
                chanChanged[CHAN_2] = 1;
            if ( addr == AUDC3_C && (pokeyChip[chip].reg[AUDCTL_C] & 0x08) )
                chanChanged[CHAN_4] = 1;
            break;
        case AUDC1_C:
        case AUDC2_C:
        case AUDC3_C:
        case AUDC4_C:
            chanChanged[addr>>1] = 1;
            pokeyChip[chip].reg[addr] = val;
            break;
        case AUDCTL_C:
            for ( i = CHAN_1; i < MAX_CHAN; ++i )
                chanChanged[i] = 1;
            pokeyChip[chip].reg[AUDCTL_C] = val;
            break;

        /*
         * Stimer just resets our MainFF output and resets counters
         *   so just return after its over
         */
        case STIMER_C:
            pokeyChip[chip].reg[addr] = val;
            tmp_event = &psEvents[eventStoreIndex];
            tmp_event->type = S_TIMER;
            tmp_event->chip = chip;
            //tmp_event->sampCount = (pokey_cpu_clock - pokeyChip[chip].lastClock) << 8;
            tmp_event->sampCount = pokey_cpu_clock;
               eventStoreIndex++;
            return;
            break;
        /*
         * Writing 0 to first 2 bits SKCTL puts POKEY in INIT state
         *   Clocks, Polys disabled       
         * Then writing a 1 to either the first 2 bits enables POKEY again
         */
        case SKCTL_C:
            if ( !(val & 0x3) ) {
                tmp_event = &psEvents[eventStoreIndex];
                tmp_event->type = START_INIT;
                tmp_event->chip = chip;
                psEvents[eventStoreIndex].sampCount = pokey_cpu_clock;
                //psEvents[eventStoreIndex].sampCount = (pokey_cpu_clock - pokeyChip[chip].lastClock) << 8;
                eventStoreIndex++;
            }
            else if ( (val | 0x3) && !(pokeyChip[chip].reg[addr] & 0x3) ) {
                tmp_event = &psEvents[eventStoreIndex];
                tmp_event->type = END_INIT;
                tmp_event->chip = chip;
                psEvents[eventStoreIndex].sampCount = pokey_cpu_clock;
                //psEvents[eventStoreIndex].sampCount = (pokey_cpu_clock - pokeyChip[chip].lastClock) << 8;
                eventStoreIndex++;
            }
            pokeyChip[chip].reg[addr] = val;
            return;
            break;
        default:
            return;
            break;
    }

    /*
     * Now create events for all that changed
     *    Store all in Pokey 0s list, for faster access later
     */
    for ( i = CHAN_1; i < MAX_CHAN; ++i ) {

        if ( chanChanged[i] ) {

               tmp_event = &psEvents[eventStoreIndex];
            tmp_event->type = CHAN;
            tmp_event->chan = i;
            tmp_event->chip = chip;
            tmp_event->volume = (pokeyChip[chip].reg[(i << 1) | (AUDC1_C)] & 0xf) << 1;
            tmp_event->volumeOnly = (pokeyChip[chip].reg[(i << 1) | (AUDC1_C)] & 0x10) ? 1 : 0;
            tmp_event->sampCount = pokey_cpu_clock;
            //tmp_event->sampCount = (pokey_cpu_clock - pokeyChip[chip].lastClock) << 8;

            /*
             * Set base clock and counter value
             */
             pokey_sound_determine_timer (chip, i, &(tmp_event->baseClock), 
                                                   &(tmp_event->counter));

            /*
             * Figure out poly mask values
             */
            pokey_sound_determine_poly (chip, i, &(tmp_event->polySel), 
                                                 &(tmp_event->poly5En));
            /*
             * Handle Hi-Pass filter
             */
            pokey_sound_determine_filter (chip, i, &(tmp_event->filterEn));

            eventStoreIndex++;

        } /* if channel changed */

    } /* end check channel for changes */

} /* end pokey_sound_reg_freq */

/******************************************************************************
**  Function   :  pokey_sound_process
**                            
**  Objective  :  This function updates the sound buffer when called from the
**                outside.
**
**  Parameters :  buffer - where sound samples get written to
**                n      - number of samples to grab
**                clks   - number of 6502 clock cycles this call covers
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_process ( unsigned char *buffer, int n, int clks ) {

    int i = -1, j;
    //int tmp_diff;
    unsigned int tmp_clock = 0;
    unsigned int total_samp_time = 0;
    unsigned int poly_index = 0;
    unsigned int sampleCounter;
    ps_chan *p_chan;
    ps_chan *p_chanf;

    if ((unsigned int)clks > pokey_cpu_clock) {
        memset(buffer, vol_silence, n*sizeof(char)); 
        pokeyChip[0].lastClock += clks;
        return;
    }

    /*
     * Calcualte sample rate based on clock coverage and number of 
     *    samples
     */
    if (!n) n = 1;
    sampleCounter = (clks<<8) / n;
    //printf ("Samp Base: %d : Samp new %d\n", pokeyChip[0].sampleCounter, sampleCounter);

    tmp_clock = 0;
    total_samp_time = pokeyChip[0].lastClock;

    /*
     * Process events that indicate greater than pokey clock
     *    This could be when the clock rolls over 0 again
     */
    while ( psEvents[eventPopIndex].type != INVALID && 
            (psEvents[eventPopIndex].sampCount > pokey_cpu_clock) ) {

        pokey_sound_process_events ( pokey_cpu_clock );
        //printf ("Never Diff: %d %d\n", pokey_cpu_clock, n);
    }

    /*
     * Walk thru num samples and fill up the buffer
     */
    while ( n-- ) {

        /*
         * Decrement counters, check for toggle, apply polys, filters
         */
        for ( i = 0; i < numPokeyChips; ++i ) {

            for ( j = CHAN_1; j < MAX_CHAN; ++j ) {

                if ( pokeyChip[i].chan[j].enabled ) {

                    p_chan = &pokeyChip[i].chan[j];

                    //p_chan->toggle -= sampleCounter;
                    p_chan->toggle -= pokeyChip[i].sampleCounter;

                    if ( p_chan->toggle <= 0 ) {

                        /*
                         * If we need a poly at all, determine the index to use
                         */
                        if ( p_chan->poly5En || p_chan->polySel ) {

                            /*
                             * The poly index is based on the end of init
                             *   and where we toggled.  We subtract the channel
                             *   since there is a 1 cycle delay from channel
                             *   to channel
                             */
                             poly_index = p_chan->toggleClk -j; 
                        }
/*
* Main    Poly5    Poly4/17Select    NewMain
* 0       0        xx                0
* 0       1        00                1
* 1       1        00                0
* 1       0        xx                1
* 0       1        01                Poly4value
* 1       1        01                !Poly4value
* 0       1        11                Poly9value
* 1       1        11                !Poly9value
* 0       1        10                Poly17value
* 1       1        10                !Poly17value
*/

                        /*
                         * Start with poly 5 flip-flop value                  _
                         *   This is actually the Not of last clocked poly 5 (Q)
                         */
                        if ( p_chan->ffPoly5Out ) {

                            /*
                             * If poly4/17 is selected, poly data clocked into
                             *     Main FF else just toggle Main FF Out
                             */
                            if (p_chan->polySel) {
                                p_chan->ffMainOut = pMask[p_chan->polySel] ?
                                    polytbls[p_chan->polySel]
                                   [abs(poly_index-pokeyChip[i].clockPolyStart[p_chan->polySel])
                                          % pMask[p_chan->polySel]] : 0;
                                  
                            }
                            else {
                                p_chan->ffMainOut ^= 0x1;
                            }
                        }

                        /*
                         * If poly 5 enable, set new output value
                         *   In the hardware the output of the poly is complimented,
                         *   but then it compliments again here, so it cancels
                         */
                        
                        if ( p_chan->poly5En ) {

                            p_chan->ffPoly5Out = poly5tbl[(poly_index-pokeyChip[i].clockPoly5Start) % 31];
                        }

                        /*
                         * Set Output (depends on HiPass)
                         */
                        pokeyChip[i].volChanBits &= ~(SET_VOL_CHAN1 << p_chan->chan);
                        switch ( p_chan->chan ) {
                            case CHAN_1:
                            case CHAN_2:
                                pokeyChip[i].volChanBits |= 
                                        (p_chan->ffMainOut ^ 
                                         p_chan->ffFilterOut) << p_chan->chan;
                                break;
                            case CHAN_3:
                            case CHAN_4:
                                pokeyChip[i].volChanBits |= 
                                    (p_chan->ffMainOut) << p_chan->chan;

                                /*
                                 * Check for this being 3 or 4 and hipass enable
                                 *    Hipass clock sets Filter = Main
                                 *    So the XOR gate to 1 or 2 output gives 0
                                 */
                                if ( pokeyChip[i].chan[p_chan->chan & 0x1].filterEn ) {
                                    p_chanf = &(pokeyChip[i].chan[p_chan->chan & 0x1]);
                                    pokeyChip[i].volChanBits &= 
                                            ~(SET_VOL_CHAN1 << p_chanf->chan);

                                    // Set filter first, we won't see for one
                                    //   clock cycle, but doesn't matter
                                    p_chanf->ffFilterOut = p_chanf->ffMainOut; 

                                    // Since fitler equals main, output is 0
                                }

                                break;
                        }

                        p_chan->toggle += p_chan->counter;
                        p_chan->toggleClk += p_chan->counter >> 8;

                    } /* toggle point happened */

                } /* if channel enabled */

            } /* for chan */

        } /* for chip */

        /*
         * Mix channels and set buffer
         */
        *buffer++ = pokeyChip[0].volTable[pokeyChip[0].volChanBits];
        samples++;

        //if ( pokeyChip[0].chan[1].volumeOnly && pokeyChip[0].chan[1].volume)
        //         printf("Buffer: %d %d %d %d %d\n", *(buffer-1), pokeyChip[0].chan[1].volume, pokeyChip[0].chan[1].chan, pokeyChip[0].volChanBits, eventPopIndex);

        tmp_clock += sampleCounter;
        total_samp_time = pokeyChip[0].lastClock + (tmp_clock>>8);

        /*
         * Process events that happened before next sample
         */
        while ( psEvents[eventPopIndex].type != INVALID && 
                (total_samp_time >= psEvents[eventPopIndex].sampCount) ) {

            pokey_sound_process_events ( total_samp_time );

        }

    } /* end while n (samples) */

    pokeyChip[0].lastClock += clks;

} /* end pokey_sound_process */

/******************************************************************************
**  Function   :  pokey_sound_process_events
**                            
**  Objective  :  This function processes the events that occurred before the 
**                current clock.
**
**  Parameters :  clk - current clock (8-bit precision) and referenced to 
**                      last clock
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_process_events ( unsigned int clk ) {

    ps_chan *p_chan;
    ps_event *p_ev;

    p_ev = &psEvents[eventPopIndex];

    switch ( p_ev->type ) {
        case INVALID:
            //printf("INVALID Processed: %d\n", eventPopIndex);
            break; // We should never get here
        case START_INIT:
            pokey_sound_start_init ( p_ev->chip, psEvents[eventPopIndex].sampCount);
            break;
        case END_INIT:
            pokey_sound_end_init ( p_ev->chip, psEvents[eventPopIndex].sampCount);
            break;
        case S_TIMER:
            pokey_sound_stimer ( p_ev->chip, (psEvents[eventPopIndex].sampCount) );
            break;
        case GTIA:
            //printf("GTIA Processed: %d\n", eventPopIndex);
            if ( p_ev->volume )
                pokeyChip[p_ev->chip].volChanBits |= SET_VOL_GTIA;
            else
                pokeyChip[p_ev->chip].volChanBits &= CLR_VOL_GTIA;
            break;
        case CHAN:

               p_chan = &pokeyChip[p_ev->chip].chan[p_ev->chan];

            /*
             * If channel disabled, try to figure out current status
             *   In the grand scheme of things, not too sure this is
             *   really important, but we'll do it anyway
             */
            pokey_sound_update_disabled_channel ( p_ev->chip, p_ev->chan, p_ev->sampCount );

            p_chan->counter = p_ev->counter;
            p_chan->polySel = p_ev->polySel;
            p_chan->poly5En = p_ev->poly5En;
            p_chan->volumeOnly = p_ev->volumeOnly;

            /*
             * Update the volume table if it has changed
             */
            if ( p_chan->volume != p_ev->volume ) {
                p_chan->volume = p_ev->volume;
                pokey_sound_volume_update ( p_ev->chip );
            }

            if ( !(p_chan->poly5En) )
                p_chan->ffPoly5Out = 1;

               if ( !(p_chan->filterEn = p_ev->filterEn) ) {
                p_chan->ffFilterOut = 1;
            }

            /*
             * Check for channel disabled
             */
            if ( !pokey_is_channel_enabled(p_ev->chip, p_ev->chan, 1) ) {

                p_chan->enabled = 0;
                p_chan->baseClock = p_ev->baseClock;

                /* FIXME: Clear this? */
                //pokeyChip[p_ev->chip].volChanBits &= ~(SET_VOL_CHAN1 << p_ev->chan);
                //if (p_chan->volumeOnly)
                    pokeyChip[p_ev->chip].volChanBits |= 
                                 (SET_VOL_CHAN1 << p_ev->chan);

                if ( !p_chan->volumeOnly ) {
                      p_chan->volume = p_ev->volume / 2;
                    pokey_sound_volume_update ( p_ev->chip );
                }
            }

            /*
             * Else enable channel and align clocks, if needed
             */
            else {

                //if ( !p_chan->enabled || (p_chan->baseClock != p_ev->baseClock) ) {
                if ( p_chan->baseClock != p_ev->baseClock ) {

                    //if (p_chan->chan == 3)
                    //    printf("Chan 4: %d %d %d\n", p_chan->volume, p_chan->counter, eventPopIndex);
                    // Figure out new toggle from old if we changed baseClock
                    //  from current value of counter, so break it down to 8bit values
                    unsigned int raw_counter;
                    raw_counter = pokey_calc_raw_counter ( p_ev->chip, 
                                                   p_ev->chan, p_chan->toggle); 

                    // Rebuild toggle to 8 bit precision value
                    unsigned int raw_clock = 0;
                       p_chan->baseClock = p_ev->baseClock;
                    if (p_chan->baseClock == CH1_CH2) {
                        raw_clock = pokey_calc_raw_counter ( p_ev->chip, CHAN_1, 
                                      pokeyChip[p_ev->chip].chan[CHAN_1].toggle); 
                    }
                    else if (p_chan->baseClock == CH3_CH4) {
                        raw_clock = pokey_calc_raw_counter ( p_ev->chip, CHAN_3, 
                                      pokeyChip[p_ev->chip].chan[CHAN_3].toggle); 
                    }

                    p_chan->toggle = pokey_calc_precision_counter (p_ev->chip, 
                                        p_ev->chan, raw_counter, raw_clock);
                   
                    pokey_sound_align_toggle ( p_ev->chip, p_chan, p_ev->sampCount );
                }

                //printf("Chan toggle: %d %d %d\n", p_chan->chan, p_chan->toggle>>8, p_ev->sampCount );
                p_chan->enabled = 1;
                //if (p_chan->counter < CPU_CYCLE_CUTOFF)
                    //printf("Processed low counter: %d 0x%x 0x%x\n", p_ev->chan, pokeyChip[0].chan[2].counter, p_chan->counter);
            }

               p_chan->baseClock = p_ev->baseClock;
               p_chan->lastEventTime = p_ev->sampCount;

            break;
    }

    p_ev->type = INVALID;

    eventPopIndex++;

} /* end pokey_sound_process_events */

/******************************************************************************
**  Function   :  pokey_sound_align_toggle
**                            
**  Objective  :  This function adjusts clock toggle point initially or if we
**                  have had channel off (ex.  when counter is 0).  Need to 
**                  make sure toggle point lines up with clock used.
**                    15KHz fires at t+77 and 64KHz fires at t+19
**                    15KHz fires every 114 and 64KHz fires every 28
**
**  Parameters :  chip    - which pokey chip this channel belongs to 
**                ps_chan - pointer to channel to set toggle for
**                clk     - pokey clock value at point of toggle point set
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_align_toggle ( int chip, ps_chan *p_chan, unsigned int clk ) {

    unsigned int tmp;
    unsigned int tmp_adj;

    switch ( p_chan->baseClock ) {
        case CH3_CH4: 
            p_chan->toggle += pokeyChip[chip].chan[CHAN_3].toggle - p_chan->toggle;
            break;
        case CH1_CH2:
            p_chan->toggle += pokeyChip[chip].chan[CHAN_1].toggle - p_chan->toggle;
            break;
        case CLK_64KHZ:
            if (clk > pokeyChip[chip].clock28Time) {
                tmp = clk - (pokeyChip[chip].clock28Time);
                tmp_adj = (tmp % 28) << 8;
                p_chan->toggle -= tmp_adj;
            }
            else {
                tmp = (pokeyChip[chip].clock28Time) - clk;
                tmp_adj = tmp << 8;
                p_chan->toggle += tmp_adj;
            }

            break;
        case CLK_15KHZ:
            if (clk > pokeyChip[chip].clock114Time) {
                tmp = clk - (pokeyChip[chip].clock114Time);
                tmp_adj = (tmp % 114) << 8;
                p_chan->toggle -= tmp_adj;
            }
            else {
                tmp = (pokeyChip[chip].clock114Time) - clk;
                tmp_adj = tmp << 8;
                p_chan->toggle += tmp_adj;
            }

            break;
    }

    if (p_chan->chan == CHAN_1 && 
            pokeyChip[chip].chan[CHAN_2].baseClock == CH1_CH2) {
        pokey_sound_align_toggle ( chip, &pokeyChip[chip].chan[CHAN_2], clk );
    }

    if (p_chan->chan == CHAN_3 && 
            pokeyChip[chip].chan[CHAN_4].baseClock == CH3_CH4) {
        pokey_sound_align_toggle ( chip, &pokeyChip[chip].chan[CHAN_4], clk );
    }

    p_chan->toggleClk = clk + (p_chan->toggle >> 8);

} /* end pokey_sound_align_toggle */

/******************************************************************************
**  Function   :  pokey_is_channel_enabled
**                            
**  Objective  :  This function determines if the channel should be enabled
**                for processing
**
**  Parameters :  chip           - which pokey chip this channel belongs to 
**                chan           - channel to check
**                upd_partner_ch - whether to check for enabled on partner ch
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
int pokey_is_channel_enabled ( int chip, int chan, int upd_partner_ch ) {

    ps_chan *p_chan;
    p_chan = &pokeyChip[chip].chan[chan];
    int enabled = 1;

    /*
     * Check for Init
     */
    if (pokeyChip[chip].inInit) {
        if (p_chan->baseClock == CLK_15KHZ || p_chan->baseClock == CLK_64KHZ )
            enabled = 0;
        if (p_chan->baseClock == CH1_CH2 && 
                (pokeyChip[chip].chan[CHAN_1].baseClock == CLK_15KHZ || 
                 pokeyChip[chip].chan[CHAN_1].baseClock == CLK_64KHZ) )
            enabled = 0;
        if (p_chan->baseClock == CH3_CH4 && 
                (pokeyChip[chip].chan[CHAN_3].baseClock == CLK_15KHZ || 
                pokeyChip[chip].chan[CHAN_3].baseClock == CLK_64KHZ) )
            enabled = 0;
    }

    /*
     * Volume Only or no Volume
     */
    if (!p_chan->volume || p_chan->volumeOnly)
        enabled = 0;

    /*
     * Check the counter for being too fast to hear
     */
    if ( (p_chan->counter <= CPU_CYCLE_CUTOFF &&  
                  !p_chan->polySel && !p_chan->poly5En))
        enabled = 0;

    /*
     * Check for filter enabled but other channel disabled
     */
    if (p_chan->filterEn && !pokeyChip[chip].chan[chan | 0x2].enabled ) {
        enabled = 0;
    }

    /*
     * If we are changing enabled, lets check partner channels for enabling
     */
    if (enabled != p_chan->enabled && upd_partner_ch) {
        if (chan == CHAN_1 && pokeyChip[chip].chan[CHAN_2].baseClock == CH1_CH2)
            pokey_is_channel_enabled(chip, CHAN_2, 0);
        if (chan == CHAN_3 && pokeyChip[chip].chan[CHAN_4].baseClock == CH3_CH4)
            pokey_is_channel_enabled(chip, CHAN_4, 0);
        if (chan == CHAN_3 && pokeyChip[chip].chan[CHAN_1].filterEn)
            pokey_is_channel_enabled(chip, CHAN_1, 0);
        if (chan == CHAN_4 && pokeyChip[chip].chan[CHAN_2].filterEn)
            pokey_is_channel_enabled(chip, CHAN_2, 0);
    }

    p_chan->enabled = enabled;

    return enabled;
     
} /* end pokey_is_channel_enabled */

/******************************************************************************
**  Function   :  pokey_calc_precision_counter
**                            
**  Objective  :  This function 
**
**  Parameters :  chip    - which pokey chip this channel belongs to 
**                ps_chan - pointer to channel to set toggle for
**                clk     - pokey clock value at point of toggle point set
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
int pokey_calc_precision_counter ( int chip, int chan, int value, int drive_clk ) {

    switch ( pokeyChip[chip].chan[chan].baseClock ) {
        case CH3_CH4: 
            if ( pokeyChip[chip].chan[CHAN_3].baseClock == CH3_179MHZ )
                      return ((value<<8) + drive_clk + 7) << 8;
            else if ( pokeyChip[chip].chan[CHAN_3].baseClock == CLK_64KHZ )
                      return (((value<<8) + drive_clk + 1) * 28) << 8;
            else
                      return (((value<<8) + drive_clk + 1) * 114) << 8;
            break;
        case CH1_CH2:
            if ( pokeyChip[chip].chan[CHAN_1].baseClock == CH1_179MHZ )
                      return ((value<<8) + drive_clk + 7) << 8;
            else if ( pokeyChip[chip].chan[CHAN_1].baseClock == CLK_64KHZ )
                      return (((value<<8) + drive_clk + 1) * 28) << 8;
            else
                      return (((value<<8) + drive_clk + 1) * 114) << 8;
            break;
        case CH1_179MHZ:
        case CH3_179MHZ:
               return (value + 4) << 8;
            break;
        case CLK_64KHZ:
               return ((value + 1) * 28) << 8;
        case CLK_15KHZ:
               return ((value + 1) * 114) << 8;
            break;
    }

    return 0;

} /* end pokey_calc_precision_counter */

/******************************************************************************
**  Function   :  pokey_calc_raw_counter
**                            
**  Objective  :  This function calculates the current value of the raw 8 bit 
**                counter from our calculated counter with precision
**
**  Parameters :  chip    - which pokey chip this channel belongs to 
**                ps_chan - pointer to channel to set toggle for
**                value   - pokey clock value at point of toggle point set
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
unsigned int pokey_calc_raw_counter ( int chip, int chan, int counter) {

    unsigned int drive_counter;
    int raw_counter = 0;

    switch ( pokeyChip[chip].chan[chan].baseClock ) {
        case CH3_CH4:
            drive_counter = pokeyChip[chip].chan[CHAN_3].toggle >> 8;
            if ( pokeyChip[chip].chan[CHAN_3].baseClock == CH3_179MHZ )
                raw_counter = (((counter >> 8) - 7) - drive_counter) >> 8;
            else if ( pokeyChip[chip].chan[CHAN_3].baseClock == CLK_64KHZ )
                raw_counter = ((((counter >> 8) / 28) - 1) - drive_counter) >> 8;
            else
                raw_counter = ((((counter >> 8) / 114) - 1) - drive_counter) >> 8;
            break;
        case CH1_CH2:
            drive_counter = pokeyChip[chip].chan[CHAN_1].toggle >> 8;
            if ( pokeyChip[chip].chan[CHAN_1].baseClock == CH1_179MHZ )
                raw_counter = (((counter >> 8) - 7) - drive_counter) >> 8;
            else if ( pokeyChip[chip].chan[CHAN_1].baseClock == CLK_64KHZ )
                raw_counter = ((((counter >> 8) / 28) - 1) - drive_counter) >> 8;
            else
                raw_counter = ((((counter >> 8) / 114) - 1) - drive_counter) >> 8;
            break;
        case CH1_179MHZ:
        case CH3_179MHZ:
               raw_counter = (counter >> 8) - 4;
            break;
        case CLK_64KHZ:
            raw_counter = ((counter >> 8) / 28) - 1;
            break;
        case CLK_15KHZ:
            raw_counter = ((counter >> 8) / 114) - 1;
            break;
    }

    return raw_counter < 0 ? 0 : raw_counter;

} /* end pokey_calc_raw_counter */

/******************************************************************************
**  Function   :  pokey_sound_stimer
**                            
**  Objective  :  This function resets counter values and chan outputs based
**                  on a write to STIMER
**
**  Parameters :  chip - which Pokey chip had a timer reset
**                clk  - current pokey cpu clock to use for timer alignment
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_stimer ( int chip, unsigned int clk ) {

    int j;

    /*
     * Main Flip Flop Output gets reset (output to 0)
     */
    for ( j = 0; j < 4; ++j )
        pokeyChip[chip].chan[j].ffMainOut = 0;

    /*
     * Reset Chan1/2 to high and 3/4 to low
     *   First two channels have high pass output that inverts ff out
     */
    if (pokeyChip[chip].chan[CHAN_1].ffFilterOut)
        pokeyChip[chip].volChanBits |= (SET_VOL_CHAN1);
    else
        pokeyChip[chip].volChanBits &= ~(SET_VOL_CHAN1);

    if (pokeyChip[chip].chan[CHAN_2].ffFilterOut)
        pokeyChip[chip].volChanBits |= (SET_VOL_CHAN2);
    else
        pokeyChip[chip].volChanBits &= ~(SET_VOL_CHAN2);

     pokeyChip[chip].volChanBits &= ~(SET_VOL_CHAN3);
     pokeyChip[chip].volChanBits &= ~(SET_VOL_CHAN4);

    /*
     * Reset the counters and align the clocks
     */
    for ( j = 0; j < 4; ++j ) {
        pokeyChip[chip].chan[j].toggle = pokeyChip[chip].chan[j].counter;
        pokeyChip[chip].chan[j].toggleClk = clk + (pokeyChip[chip].chan[j].counter>>8);
        if (pokeyChip[chip].chan[j].enabled) {

            pokey_sound_align_toggle ( chip, &pokeyChip[chip].chan[j], clk );
        }
    }

} /* end pokey_sound_stimer */

/******************************************************************************
**  Function   :  pokey_sound_start_end_init
**                            
**  Objective  :  These functions are called when SKCTL is written 0 (start)
**                  and then non-zero to the first 2 bits
**
**  Parameters :  chip - the chip to init
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_start_init ( int chip, unsigned int clk ) {

    int i;

    /*
     * Get disabled channels updated to here
     */
    for ( i = CHAN_1; i < MAX_CHAN; ++i ) {
        pokey_sound_update_disabled_channel ( chip, i, clk );
    }

    clear_poly_mask(); /* cause polys to indicate 0s */

    /*
     * The 1.79 MHz can run during init, otherwise we disable
     */
    for ( i = CHAN_1; i < MAX_CHAN; ++i ) {
        switch ( pokeyChip[chip].chan[i].baseClock ) {
            case CH3_CH4:
                if ( pokeyChip[chip].chan[CHAN_3].baseClock != CH3_179MHZ )
                    pokeyChip[chip].chan[i].enabled = 0;
                break;
            case CH1_CH2:
                if ( pokeyChip[chip].chan[CHAN_1].baseClock != CH1_179MHZ )
                    pokeyChip[chip].chan[i].enabled = 0;
                break;
            case CLK_64KHZ:
            case CLK_15KHZ:
                pokeyChip[chip].chan[i].enabled = 0;
                break;
        }
    }

    pokeyChip[chip].inInit = 1;

} /* end pokey_sound_start_init */

void pokey_sound_end_init ( int chip, unsigned int clk ) {

    int i;

    set_poly_mask();

    pokeyChip[chip].inInit = 0;
    pokeyChip[chip].clock114Time = clk + 77;
    pokeyChip[chip].clock28Time = clk + 19;
    pokeyChip[chip].clockPoly5Start = clk;
    for ( i = 0; i < MAX_POLY; ++i ) {
        pokeyChip[chip].clockPolyStart[i] = clk;
    }

    /*
     * Enabled needed channels and align their clocks
     */
    for ( i = CHAN_1; i < MAX_CHAN; ++i ) {
        pokey_sound_align_toggle ( chip, &pokeyChip[chip].chan[i], clk );
    }

} /* end pokey_sound_end_init */

/******************************************************************************
**  Function   :  pokey_sound_update_disabled_channel
**                            
**  Objective  :  This function figures out current status of a disabled chan
**                  since it is not being kept up with real-time
**
**  Parameters :  chip - chip to setup the vol table for  
**                chan - channel to update
**                clk  - clock value to check at
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_update_disabled_channel ( int chip, int chan, unsigned int clk ) {

    ps_chan *p_chan;

    if (pokeyChip[chip].inInit)
        return;

    p_chan = &pokeyChip[chip].chan[chan];

    if (p_chan->enabled)
        return;

    int oldPoly5Out = 1;
    unsigned int timeSinceToggle;
    unsigned int poly_index;

    p_chan->ffPoly5Out = 1;

    // Find first toggle after last event
    timeSinceToggle = clk - p_chan->lastEventTime + (p_chan->toggle>>8);

    // Figure out current toggle based on mod with counter
    p_chan->toggle = (timeSinceToggle % (p_chan->counter>>8)) << 8;
    p_chan->toggleClk = clk + (p_chan->toggle >> 8);

    // Poly 5 flip-flop
   if (p_chan->poly5En || p_chan->polySel) {
       poly_index = clk - (p_chan->toggle>>8) - pokeyChip[chip].clockPoly5Start - p_chan->chan;
       if (p_chan->poly5En) { 
           p_chan->ffPoly5Out = poly5tbl[poly_index % 31];
           poly_index -= p_chan->counter>>8;
           oldPoly5Out = poly5tbl[poly_index % 31];
           poly_index += p_chan->counter>>8;
       }
       poly_index += pokeyChip[chip].clockPoly5Start;
   }

   // Output Flip-Flop
   if (oldPoly5Out) {
       if (p_chan->polySel) {
           poly_index -= pokeyChip[chip].clockPolyStart[p_chan->polySel];
           
           p_chan->ffMainOut = pMask[p_chan->polySel] ?
                polytbls[p_chan->polySel]
               [(poly_index) % pMask[p_chan->polySel]] : 0;

           p_chan->ffMainOut = polytbls[p_chan->polySel]
                                    [poly_index % pMask[p_chan->polySel]];
       }
       else {
           // Only change value on odd pulse number
           if ( (timeSinceToggle / (p_chan->counter>>8)) & 0x1)
               p_chan->ffMainOut ^= 0x1;
       }
   }

   p_chan->lastEventTime = clk;

} /* end pokey_sound_update_disabled_channel */

/******************************************************************************
**  Function   :  pokey_sound_volume_update
**                            
**  Objective  :  This function recalculates the volume table if a value
**                  changed.
**
**  Parameters :  chip - chip to setup the vol table for  
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_volume_update ( int chip ) {

    int i;
    int tmp;

    for ( i = 0; i < 32; ++i ) {

        tmp = vol_silence;

        if ( i & SET_VOL_CHAN1 )
            tmp += pokeyChip[chip].chan[CHAN_1].volume;
        if ( i & SET_VOL_CHAN2 )
            tmp += pokeyChip[chip].chan[CHAN_2].volume;
        if ( i & SET_VOL_CHAN3 )
            tmp += pokeyChip[chip].chan[CHAN_3].volume;
        if ( i & SET_VOL_CHAN4 )
            tmp += pokeyChip[chip].chan[CHAN_4].volume;
        if ( i & SET_VOL_GTIA )
            tmp += 16;

        pokeyChip[chip].volTable[i] = tmp;
    }

} /* end pokey_sound_volume_update */

/******************************************************************************
**  Function   :  pokey_sound_update_gtia_consol
**                            
**  Objective  :  This function is called when gtia consol value changes to
**                  update the volume to speaker from gtia
**
**  Parameters :  val - value of gtia speaker bit
**                                                
**  return     :  NONE
**      
******************************************************************************/ 
void pokey_sound_update_gtia_consol ( unsigned int val ) {

    ps_event *tmp_event;

    tmp_event = &psEvents[eventStoreIndex];
    tmp_event->type = GTIA;
    tmp_event->chip = 0;
    tmp_event->volume = val ? 0 : 16;
    tmp_event->sampCount = pokey_cpu_clock;
    //printf("GTIA: count: %d %d\n", tmp_event->sampCount, eventStoreIndex);
    eventStoreIndex++;

} /* end pokey_sound_update_gtia_consol */

