home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / Atari800 / pokey11.c < prev    next >
C/C++ Source or Header  |  1998-02-17  |  33KB  |  1,012 lines

  1. /*****************************************************************************/
  2. /*                                                                           */
  3. /* Module:  POKEY Chip Simulator, V1.2                                       */
  4. /* Purpose: To emulate the sound generation hardware of the Atari POKEY chip.*/
  5. /* Author:  Ron Fries                                                        */
  6. /*          Thomas Richter                                                   */
  7. /* Date:    September 22, 1996                                               */
  8. /*          February 17,1998                                                 */
  9. /*                                                                           */
  10. /*****************************************************************************/
  11. /*                                                                           */
  12. /*                 License Information and Copyright Notice                  */
  13. /*                 ========================================                  */
  14. /*                                                                           */
  15. /* PokeySound is Copyright(c) 1996 by Ron Fries                              */
  16. /*                                                                           */
  17. /* This library is free software; you can redistribute it and/or modify it   */
  18. /* under the terms of version 2 of the GNU Library General Public License    */
  19. /* as published by the Free Software Foundation.                             */
  20. /*                                                                           */
  21. /* This library is distributed in the hope that it will be useful, but       */
  22. /* WITHOUT ANY WARRANTY; without even the implied warranty of                */
  23. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library */
  24. /* General Public License for more details.                                  */
  25. /* To obtain a copy of the GNU Library General Public License, write to the  */
  26. /* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */
  27. /*                                                                           */
  28. /* Any permitted reproduction of these routines, in whole or in part, must   */
  29. /* bear this legend.                                                         */
  30. /*                                                                           */
  31. /*****************************************************************************/
  32.  
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <time.h>
  36.  
  37. #include "pokey.h"
  38. #include "pokey11.h"
  39. #include "sio.h"
  40. #include "mem.h"
  41. #include "cpu.h"
  42. #include "platform.h"
  43.  
  44. /* CONSTANT DEFINITIONS */
  45.  
  46. /* definitions for AUDCx (D201, D203, D205, D207) */
  47. #define NOTPOLY5    0x80     /* selects POLY5 or direct CLOCK */
  48. #define POLY4       0x40     /* selects POLY4 or POLY17 */
  49. #define PURE        0x20     /* selects POLY4/17 or PURE tone */
  50. #define VOL_ONLY    0x10     /* selects VOLUME OUTPUT ONLY */
  51. #define VOLUME_MASK 0x0f     /* volume mask */
  52.  
  53. /* definitions for AUDCTL (D208) */
  54. #define POLY9       0x80     /* selects POLY9 or POLY17 */
  55. #define CH1_179     0x40     /* selects 1.78979 MHz for Ch 1 */
  56. #define CH3_179     0x20     /* selects 1.78979 MHz for Ch 3 */
  57. #define CH1_CH2     0x10     /* clocks channel 1 w/channel 2 */
  58. #define CH3_CH4     0x08     /* clocks channel 3 w/channel 4 */
  59. #define CH1_FILTER  0x04     /* selects channel 1 high pass filter */
  60. #define CH2_FILTER  0x02     /* selects channel 2 high pass filter */
  61. #define CLOCK_15    0x01     /* selects 15.6999kHz or 63.9210kHz */
  62.  
  63.  
  64. /* for accuracy, the 64kHz and 15kHz clocks are exact divisions of
  65.    the 1.79MHz clock */
  66. #define DIV_64      28       /* divisor for 1.79MHz clock to 64 kHz */
  67. #define DIV_15      114      /* divisor for 1.79MHz clock to 15 kHz */
  68.  
  69. /* the size (in entries) of the 4 polynomial tables */
  70. #define POLY4_SIZE  0x000f
  71. #define POLY5_SIZE  0x001f
  72. #define POLY9_SIZE  0x01ff
  73.  
  74. #ifdef COMP16                           /* if 16-bit compiler */
  75. #define POLY17_SIZE 0x00007fffL    /* reduced to 15 bits for simplicity */
  76. #else
  77. #define POLY17_SIZE 0x0001ffffL    /* else use the full 17 bits */
  78. #endif
  79.  
  80.  
  81. #define FALSE       0
  82. #define TRUE        1
  83.  
  84.  
  85. /* GLOBAL VARIABLE DEFINITIONS */
  86.  
  87. /* structures to hold the 9 pokey control bytes */ 
  88. UBYTE AUDF[4];    /* AUDFx (D200, D202, D204, D206) */
  89. UBYTE AUDC[4];    /* AUDCx (D201, D203, D205, D207) */
  90. UBYTE AUDCTL;     /* AUDCTL (D208) */      
  91.  
  92. static UBYTE Outbit[4];  /* current state of the output (high or low) */
  93.  
  94. static UBYTE Outvol[4];  /* last output volume for each channel */
  95.  
  96. int DELAYED_SERIN_IRQ;
  97. int DELAYED_SEROUT_IRQ;
  98. int DELAYED_XMTDONE_IRQ;
  99.  
  100. /* Initialze the bit patterns for the polynomials. */
  101.  
  102. /* The 4bit and 5bit patterns are the identical ones used in the pokey chip. */
  103. /* Though the patterns could be packed with 8 bits per byte, using only a */
  104. /* single bit per byte keeps the math simple, which is important for */
  105. /* efficient processing. */
  106.  
  107. static UBYTE bit4[POLY4_SIZE] = 
  108.       { 1,1,0,1,1,1,0,0,0,0,1,0,1,0,0 };
  109.  
  110. static UBYTE bit5[POLY5_SIZE] = 
  111.       { 0,0,1,1,0,0,0,1,1,1,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,0,0,0,0,0,1 };
  112.  
  113. static UBYTE bit17[POLY17_SIZE];  /* Rather than have a table with 131071 */
  114.                             /* entries, I use a random number generator. */
  115.                             /* It shouldn't make much difference since */
  116.                             /* the pattern rarely repeats anyway. */
  117.  
  118. static ULONG Poly17_size; /* global for the poly 17 size, since it can */
  119.                            /* be changed from 17 bit to 9 bit */
  120.  
  121. static ULONG Poly_adjust; /* the amount that the polynomial will need */
  122.                            /* to be adjusted to process the next bit */
  123.  
  124. static ULONG  P4=0,   /* Global position pointer for the 4-bit  POLY array */
  125.               P5=0,   /* Global position pointer for the 5-bit  POLY array */
  126.               P17=0;  /* Global position pointer for the 17-bit POLY array */
  127.  
  128. ULONG         Div_n_cnt[4],   /* Divide by n counter. one for each channel */
  129.               Div_n_max[4],   /* Divide by n maximum, one for each channel */
  130.               Div_n_irq[4];   /* Just the same counter, but used for IRQ */
  131.  
  132. static ULONG Samp_n_max,     /* Sample max.  For accuracy, it is *256 */
  133.              Samp_n_cnt[2];  /* Sample cnt. */
  134.  
  135. static ULONG Base_mult;      /* selects either 64Khz or 15Khz clock mult */
  136.  
  137. UBYTE KBCODE;
  138. UBYTE IRQST;
  139. UBYTE IRQEN;
  140. UBYTE SKSTAT;
  141.  
  142. static char *rcsid = "$Id: pokey11.c,v 1.2 1998/02/17 Ron Fries,thor";
  143.  
  144. extern UWORD regPC;
  145.  
  146. void Update_Sound(int chan_mask);
  147.        
  148. /*****************************************************************************/
  149. /* In my routines, I treat the sample output as another divide by N counter  */
  150. /* For better accuracy, the Samp_n_cnt has a fixed binary decimal point      */
  151. /* which has 8 binary digits to the right of the decimal point.  I use a two */
  152. /* byte array to give me a minimum of 40 bits, and then use pointer math to  */
  153. /* reference either the 24.8 whole/fraction combination or the 32-bit whole  */
  154. /* only number.  This is mainly used to keep the math simple for             */
  155. /* optimization. See below:                                                  */
  156. /*                                                                           */
  157. /* xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | xxxxxxxx xxxxxxxx xxxxxxxx.xxxxxxxx */
  158. /*  unused   unused   unused    whole      whole    whole    whole  fraction */
  159. /*                                                                           */
  160. /* Samp_n_cnt[0] gives me a 32-bit int 24 whole bits with 8 fractional bits, */
  161. /* while (ULONG *)((UBYTE *)(&Samp_n_cnt[0])+1) gives me the 32-bit whole   */
  162. /* number only.                                                              */
  163. /*****************************************************************************/
  164.  
  165. /* Register GET routines */
  166.  
  167. mtype POKEY_KBCODE_GET(void)
  168. {
  169.   return KBCODE;
  170. }
  171.  
  172. mtype POKEY_IRQST_GET(void)
  173. {
  174.   return IRQST;
  175. }
  176.  
  177. mtype POKEY_POT0_GET(void)
  178. {
  179.   return Atari_POT(0);
  180. }
  181.  
  182. mtype POKEY_POT1_GET(void)
  183. {
  184.   return Atari_POT(1);
  185. }
  186.  
  187. mtype POKEY_POT2_GET(void)
  188. {
  189.   return Atari_POT(2);
  190. }
  191.  
  192. mtype POKEY_POT3_GET(void)
  193. {
  194.   return Atari_POT(3);
  195. }
  196.  
  197. mtype POKEY_POT4_GET(void)
  198. {
  199.   return Atari_POT(4);
  200. }
  201.  
  202. mtype POKEY_POT5_GET(void)
  203. {
  204.   return Atari_POT(5);
  205. }
  206.  
  207. mtype POKEY_POT6_GET(void)
  208. {
  209.   return Atari_POT(6);
  210. }
  211.  
  212. mtype POKEY_POT7_GET(void)
  213. {
  214.   return Atari_POT(7);
  215. }
  216.  
  217. mtype POKEY_RANDOM_GET(void)
  218. {
  219. static int rand_init = 0;
  220.  
  221.   if (!rand_init) {
  222.     srand((int) time((time_t *) NULL));
  223.     rand_init = 1;
  224.   }
  225.   return rand();
  226. }
  227.  
  228. mtype POKEY_SERIN_GET(void)
  229. {
  230.   return SIO_GetByte();
  231. }
  232.  
  233. mtype POKEY_SKSTAT_GET(void)
  234. {
  235. #ifdef BASIC
  236.   return 0xff;
  237. #else
  238.   return Atari_Keyboard_State();
  239. #endif
  240. }
  241.  
  242.  
  243. /* IO Put routines */
  244.  
  245. int POKEY_AUDF1_PUT(mtype val)
  246. {
  247.   AUDF[CHAN1] = val;
  248.   Update_Sound((AUDCTL & CH1_CH2)?((1<<CHAN2)|(1<<CHAN1)):(1<<CHAN1));
  249.   return FALSE;
  250. }
  251.  
  252. int POKEY_AUDC1_PUT(mtype val)
  253. {
  254.   AUDC[CHAN1] = val;
  255.   Update_Sound(1<<CHAN1);
  256.   return FALSE;
  257. }
  258.  
  259. int POKEY_AUDF2_PUT(mtype val)
  260. {
  261.   AUDF[CHAN2] = val;
  262.   Update_Sound(1<<CHAN2);
  263.   return FALSE;
  264. }
  265.  
  266. int POKEY_AUDC2_PUT(mtype val)
  267. {
  268.   AUDC[CHAN2] = val;
  269.   Update_Sound(1<<CHAN2);
  270.   return FALSE;
  271. }
  272.  
  273. int POKEY_AUDF3_PUT(mtype val)
  274. {
  275.   AUDF[CHAN3] = val;
  276.   Update_Sound((AUDCTL & CH3_CH4)?((1<<CHAN4)|(1<<CHAN3)):(1<<CHAN3));
  277.   return FALSE;
  278. }
  279.  
  280. int POKEY_AUDC3_PUT(mtype val)
  281. {
  282.   AUDC[CHAN3] = val;
  283.   Update_Sound(1<<CHAN3);
  284.   return FALSE;
  285. }
  286.  
  287. int POKEY_AUDF4_PUT(mtype val)
  288. {
  289.   AUDF[CHAN4] = val;
  290.   Update_Sound(1<<CHAN4);
  291.   return FALSE;
  292. }
  293.  
  294. int POKEY_AUDC4_PUT(mtype val)
  295. {
  296.   AUDC[CHAN4] = val;
  297.   Update_Sound(1<<CHAN4);
  298.   return FALSE;
  299. }
  300.  
  301. int POKEY_AUDCTL_PUT(mtype val)
  302. {
  303.   AUDCTL = val;
  304.  
  305.   if (AUDCTL & POLY9)
  306.     Poly17_size = POLY9_SIZE;
  307.   else
  308.     Poly17_size = POLY17_SIZE;
  309.       
  310.   /* determine the base multiplier for the 'div by n' calculations */
  311.   if (AUDCTL & CLOCK_15)
  312.     Base_mult = DIV_15;
  313.   else
  314.     Base_mult = DIV_64;
  315.   
  316.   Update_Sound((1<<CHAN1)|(1<<CHAN2)|(1<<CHAN3)|(1<<CHAN4));
  317.   return FALSE;
  318. }
  319.  
  320. int POKEY_IRQEN_PUT(mtype val)
  321. {
  322.   IRQEN = val;
  323.   IRQST |= ~val;
  324.   return FALSE;
  325. }
  326.  
  327. int POKEY_SEROUT_PUT(mtype val)
  328. {
  329.   if ((SKSTAT & 0x70) == 0x20) {
  330.     if ((AUDF[CHAN3] == 0x28) && (AUDF[CHAN4] == 0x00) && (AUDCTL & 0x28)==0x28)
  331.       SIO_PutByte(val);
  332.   }
  333.   return FALSE;
  334. }
  335.  
  336. int POKEY_STIMER_PUT(mtype val)
  337. {
  338.   Div_n_cnt[CHAN1]=Div_n_irq[CHAN1]=0;
  339.   Div_n_cnt[CHAN2]=Div_n_irq[CHAN2]=0;
  340.   Div_n_cnt[CHAN3]=Div_n_irq[CHAN3]=0;
  341.   Div_n_cnt[CHAN4]=Div_n_irq[CHAN4]=0;
  342.   return FALSE;
  343. }
  344.  
  345. int POKEY_SKSTAT_PUT(mtype val)
  346. {
  347.   SKSTAT = val;
  348.   return FALSE;
  349. }
  350.  
  351.  
  352. /*****************************************************************************/
  353. /* Module:  Pokey_sound_init()                                               */
  354. /* Purpose: to handle the power-up initialization functions                  */
  355. /*          these functions should only be executed on a cold-restart        */
  356. /*                                                                           */
  357. /* Author:  Ron Fries                                                        */
  358. /* Date:    September 22, 1996                                               */
  359. /*                                                                           */
  360. /* Inputs:  freq17 - the value for the '1.79MHz' Pokey audio clock           */
  361. /*          playback_freq - the playback frequency in samples per second     */
  362. /*                                                                           */
  363. /* Outputs: Adjusts local globals - no return value                          */
  364. /*                                                                           */
  365. /*****************************************************************************/
  366.  
  367. void Init_Pokey(int *argc,char **argv,int base)
  368. {
  369. int chan;
  370. long n;
  371.  
  372.    /* fill the 17bit polynomial with random bits */
  373.    for (n=0; n<POLY17_SIZE; n++)
  374.    {
  375.       bit17[n] = rand() & 0x01;       /* fill poly 17 with random bits */
  376.    }
  377.  
  378.    /* start all of the polynomial counters at zero */
  379.    Poly_adjust = 0;
  380.    P4 = 0;
  381.    P5 = 0;
  382.    P17 = 0;
  383.  
  384.    Samp_n_cnt[0] = 0;  /* initialize all bits of the sample */
  385.    Samp_n_cnt[1] = 0;  /* 'divide by N' counter */
  386.  
  387.    Poly17_size = POLY17_SIZE;
  388.    for (chan = CHAN1; chan <= CHAN4; chan++)
  389.      {
  390.        Outvol[chan] = 0;
  391.        Outbit[chan] = 0;
  392.        Div_n_cnt[chan] = 0;
  393.        Div_n_irq[chan] = 0;
  394.        Div_n_max[chan] = 0x7fffffffL;
  395.        AUDC[chan] = 0;
  396.        AUDF[chan] = 0;
  397.      }
  398.   
  399.    AUDCTL = 0;
  400.    IRQST = 0xff;
  401.    IRQEN = 0x00;
  402.    Base_mult = DIV_64;  
  403.    /*
  404.     * Initialise Serial Port Interrupts
  405.     */
  406.   
  407.    DELAYED_SERIN_IRQ = 0;
  408.    DELAYED_SEROUT_IRQ = 0;
  409.    DELAYED_XMTDONE_IRQ = 0;
  410.  
  411.    if (argc)
  412.      Samp_n_max = 1;   /* provide some meaningfull default if hard reset */
  413.  
  414.    SetHW(base+_AUDF1,0xff0f,&POKEY_POT0_GET,&POKEY_AUDF1_PUT);
  415.    SetHW(base+_AUDC1,0xff0f,&POKEY_POT1_GET,&POKEY_AUDC1_PUT);
  416.    SetHW(base+_AUDF2,0xff0f,&POKEY_POT2_GET,&POKEY_AUDF2_PUT);
  417.    SetHW(base+_AUDC2,0xff0f,&POKEY_POT3_GET,&POKEY_AUDC2_PUT);
  418.    SetHW(base+_AUDF3,0xff0f,&POKEY_POT4_GET,&POKEY_AUDF3_PUT);
  419.    SetHW(base+_AUDC3,0xff0f,&POKEY_POT5_GET,&POKEY_AUDC3_PUT);
  420.    SetHW(base+_AUDF4,0xff0f,&POKEY_POT6_GET,&POKEY_AUDF4_PUT);
  421.    SetHW(base+_AUDC4,0xff0f,&POKEY_POT7_GET,&POKEY_AUDC4_PUT);
  422.    SetHW(base+_AUDCTL,0xff0f,NULL,&POKEY_AUDCTL_PUT);
  423.    SetHW(base+_STIMER,0xff0f,&POKEY_KBCODE_GET,&POKEY_STIMER_PUT);
  424.    SetHW(base+_SKRES,0xff0f,&POKEY_RANDOM_GET,NULL);
  425.    SetHW(base+_POTGO,0xff0f,NULL,NULL);
  426.    SetHW(base+_SEROUT,0xff0f,&POKEY_SERIN_GET,&POKEY_SEROUT_PUT);
  427.    SetHW(base+_IRQEN,0xff0f,&POKEY_IRQST_GET,&POKEY_IRQEN_PUT);
  428.    SetHW(base+_SKCTLS,0xff0f,&POKEY_SKSTAT_GET,&POKEY_SKSTAT_PUT);
  429. }
  430.  
  431. void Pokey_sound_init (ULONG freq17, UWORD playback_freq)
  432. {
  433.    Samp_n_max = ((ULONG)freq17 << 8) / playback_freq;
  434. }
  435.  
  436.  
  437. /*****************************************************************************/
  438. /* Module:  Update_Sound()                                                   */
  439. /* Purpose: To process the latest control values stored in the AUDF, AUDC,   */
  440. /*          and AUDCTL registers.  It pre-calculates as much information as  */
  441. /*          possible for better performance.  This routine has not been      */
  442. /*          optimized.                                                       */
  443. /*                                                                           */
  444. /* Author:  Ron Fries                                                        */
  445. /* Date:    September 22, 1996                                               */
  446. /*                                                                           */
  447. /* Inputs:  addr - the address of the parameter to be changed                */
  448. /*          val - the new value to be placed in the specified address        */
  449. /*                                                                           */
  450. /* Outputs: Adjusts local globals - no return value                          */
  451. /*                                                                           */
  452. /*****************************************************************************/
  453.  
  454. void Update_Sound(int chan_mask)
  455. {
  456. ULONG new_val = 0;
  457. int chan;
  458.  
  459.     /************************************************************/
  460.     /* As defined in the manual, the exact Div_n_cnt values are */
  461.     /* different depending on the frequency and resolution:     */
  462.     /*    64 kHz or 15 kHz - AUDF + 1                           */
  463.     /*    1 MHz, 8-bit -     AUDF + 4                           */
  464.     /*    1 MHz, 16-bit -    AUDF[CHAN1]+256*AUDF[CHAN2] + 7    */
  465.     /************************************************************/
  466.  
  467.     /* only reset the channels that have changed */
  468.  
  469.     if (chan_mask & (1 << CHAN1))
  470.     {
  471.        /* process channel 1 frequency */
  472.        if (AUDCTL & CH1_179)
  473.           new_val = AUDF[CHAN1] + 4;
  474.        else
  475.           new_val = (AUDF[CHAN1] + 1) * Base_mult;
  476.  
  477.        if (new_val != Div_n_max[CHAN1])
  478.        {
  479.           Div_n_max[CHAN1] = new_val;
  480.           Div_n_cnt[CHAN1] = 0;
  481.       Div_n_irq[CHAN1] = 0;
  482.        }
  483.     }
  484.  
  485.     if (chan_mask & (1 << CHAN2))
  486.     {
  487.        /* process channel 2 frequency */
  488.        if (AUDCTL & CH1_CH2)
  489.           if (AUDCTL & CH1_179)
  490.              new_val = AUDF[CHAN2] * 256 + AUDF[CHAN1] + 7;
  491.           else
  492.              new_val = (AUDF[CHAN2] * 256 + AUDF[CHAN1] + 1) * Base_mult;
  493.        else
  494.           new_val = (AUDF[CHAN2] + 1) * Base_mult;
  495.  
  496.        if (new_val != Div_n_max[CHAN2])
  497.        {
  498.           Div_n_max[CHAN2] = new_val;
  499.           Div_n_cnt[CHAN2] = 0;
  500.       Div_n_irq[CHAN2] = 0;
  501.        }
  502.     }
  503.  
  504.     if (chan_mask & (1 << CHAN3))
  505.     {
  506.        /* process channel 3 frequency */
  507.        if (AUDCTL & CH3_179)
  508.           new_val = AUDF[CHAN3] + 4;
  509.        else
  510.           new_val= (AUDF[CHAN3] + 1) * Base_mult;
  511.  
  512.        if (new_val!= Div_n_max[CHAN3])
  513.        {
  514.           Div_n_max[CHAN3] = new_val;
  515.           Div_n_cnt[CHAN3] = 0;
  516.       Div_n_irq[CHAN3] = 0;
  517.        }
  518.     }
  519.  
  520.     if (chan_mask & (1 << CHAN4))
  521.     {
  522.        /* process channel 4 frequency */
  523.        if (AUDCTL & CH3_CH4)
  524.           if (AUDCTL & CH3_179)
  525.              new_val = AUDF[CHAN4] * 256 + AUDF[CHAN3] + 7;
  526.           else
  527.              new_val = (AUDF[CHAN4] * 256 + AUDF[CHAN3] + 1) * Base_mult;
  528.        else
  529.           new_val = (AUDF[CHAN4] + 1) * Base_mult;
  530.  
  531.        if (new_val != Div_n_max[CHAN4])
  532.        {
  533.           Div_n_max[CHAN4] = new_val;
  534.           Div_n_cnt[CHAN4] = 0;
  535.       Div_n_irq[CHAN4] = 0;
  536.        }
  537.     }
  538.  
  539.     /* if channel is volume only, set current output */
  540.     for (chan = CHAN1; chan <= CHAN4; chan++)
  541.     {
  542.        if (chan_mask & (1 << chan))
  543.        {
  544.           /* I've disabled any frequencies that exceed the sampling
  545.              frequency.  There isn't much point in processing frequencies
  546.              that the hardware can't reproduce.  I've also disabled 
  547.              processing if the volume is zero. */
  548.  
  549.           /* if the channel is volume only */
  550.           /* or the channel is off (volume == 0) */
  551.           /* or the channel freq is greater than the playback freq */
  552.           if ((AUDC[chan] & VOL_ONLY) ||
  553.              ((AUDC[chan] & VOLUME_MASK) == 0) ||
  554.               (Div_n_max[chan] < (Samp_n_max >> 8)))
  555.           {
  556.              /* then set the channel to the selected volume */
  557.              Outvol[chan] = AUDC[chan] & VOLUME_MASK;
  558.              /* and set channel freq to max to reduce processing */
  559.              /* Div_n_max[chan] = 0x7fffffffL;
  560.         Removed. Conflicts with POKEY-IRQs */
  561.           }
  562.        }
  563.     } 
  564. }
  565.  
  566.  
  567. /*****************************************************************************/
  568. /* Module:  Pokey_process_2()                                                */
  569. /* Purpose: To fill the output buffer with the sound output based on the     */
  570. /*          pokey chip parameters.  This routine has not been optimized.     */
  571. /*          Though it is not used by the program, I've left it for reference.*/
  572. /*                                                                           */
  573. /* Author:  Ron Fries                                                        */
  574. /* Date:    September 22, 1996                                               */
  575. /*                                                                           */
  576. /* Inputs:  *buffer - pointer to the buffer where the audio output will      */
  577. /*                    be placed                                              */
  578. /*          n - size of the playback buffer                                  */
  579. /*                                                                           */
  580. /* Outputs: the buffer will be filled with n bytes of audio - no return val  */
  581. /*                                                                           */
  582. /*****************************************************************************/
  583.  
  584. void Pokey_process_2 (register unsigned char *buffer, register UWORD n)
  585. {
  586. #ifdef VOXWARE
  587.     register ULONG *samp_cnt_w_ptr;
  588.     register ULONG event_min;
  589.     register UBYTE next_event;
  590.     register UBYTE cur_val;
  591.     register UBYTE chan;
  592.  
  593.     /* set a pointer to the whole portion of the samp_n_cnt */
  594.     samp_cnt_w_ptr = (ULONG *)((UBYTE *)(&Samp_n_cnt[0])+1);
  595.  
  596.     /* loop until the buffer is filled */
  597.     while (n)
  598.     {
  599.        /* Normally the routine would simply decrement the 'div by N' */
  600.        /* counters and react when they reach zero.  Since we normally */
  601.        /* won't be processing except once every 80 or so counts, */
  602.        /* I've optimized by finding the smallest count and then */
  603.        /* 'accelerated' time by adjusting all pointers by that amount. */
  604.  
  605.        /* find next smallest event (either sample or chan 1-4) */
  606.        next_event = SAMPLE;
  607.        event_min = *samp_cnt_w_ptr;
  608.  
  609.        for (chan = CHAN1; chan <= CHAN4; chan++)
  610.        {
  611.           if (Div_n_cnt[chan] <= event_min)
  612.           {
  613.              event_min = Div_n_cnt[chan];
  614.              next_event = chan;
  615.           }
  616.        }
  617.  
  618.  
  619.        /* decrement all counters by the smallest count found */
  620.        for (chan = CHAN1; chan <= CHAN4; chan++)
  621.        {
  622.           Div_n_cnt[chan] -= event_min;
  623.        }
  624.  
  625.        *samp_cnt_w_ptr -= event_min;
  626.  
  627.        /* since the polynomials require a mod (%) function which is 
  628.           division, I don't adjust the polynomials on the SAMPLE events,
  629.           only the CHAN events.  I have to keep track of the change,
  630.           though. */
  631.        Poly_adjust += event_min;
  632.  
  633.        /* if the next event is a channel change */
  634.        if (next_event != SAMPLE)
  635.        {
  636.           /* shift the polynomial counters */
  637.           P4  = (P4  + Poly_adjust) % POLY4_SIZE;
  638.           P5  = (P5  + Poly_adjust) % POLY5_SIZE;
  639.           P17 = (P17 + Poly_adjust) % Poly17_size;
  640.          
  641.           /* reset the polynomial adjust counter to zero */
  642.           Poly_adjust = 0;
  643.  
  644.           /* adjust channel counter */
  645.           Div_n_cnt[next_event] += Div_n_max[next_event];
  646.  
  647.           /* From here, a good understanding of the hardware is required */
  648.           /* to understand what is happening.  I won't be able to provide */
  649.           /* much description to explain it here. */
  650.  
  651.           /* if the output is pure or the output is poly5 and the poly5 bit */
  652.           /* is set */
  653.           if ((AUDC[next_event] & NOTPOLY5) || bit5[P5])
  654.           {
  655.              /* if the PURE bit is set */
  656.              if (AUDC[next_event] & PURE)
  657.              {
  658.                 /* then simply toggle the output */
  659.                 Outbit[next_event] = !Outbit[next_event];
  660.              }
  661.              /* otherwise if POLY4 is selected */
  662.              else if (AUDC[next_event] & POLY4)
  663.              {
  664.                 /* then use the poly4 bit */
  665.                 Outbit[next_event] = bit4[P4];
  666.              }
  667.              else
  668.              {
  669.                 /* otherwise use the poly17 bit */
  670.                 Outbit[next_event] = bit17[P17];
  671.              }
  672.           }
  673.  
  674.           /* At this point I haven't emulated the filters.  Though I don't
  675.              expect it to be complicated, I don't believe this feature is
  676.              used much anyway.  I'll work on it later. */
  677.           if ((next_event == CHAN1) || (next_event == CHAN3))
  678.           {
  679.              /* INSERT FILTER HERE */
  680.           }
  681.  
  682.           /* if the current output bit is set */
  683.           if (Outbit[next_event])
  684.           {
  685.              /* then set to the current volume */
  686.              Outvol[next_event] = AUDC[next_event] & VOLUME_MASK;
  687.           }
  688.           else
  689.           {
  690.              /* set the volume to zero */
  691.              Outvol[next_event] = 0;
  692.           }
  693.        }
  694.        else /* otherwise we're processing a sample */
  695.        {
  696.           /* adjust the sample counter - note we're using the 24.8 integer
  697.              which includes an 8 bit fraction for accuracy */
  698.           *Samp_n_cnt += Samp_n_max;
  699.  
  700.           cur_val = 0;
  701.  
  702.           /* add the output values of all 4 channels */
  703.           for (chan = CHAN1; chan <= CHAN4; chan++)
  704.           {
  705.              cur_val += Outvol[chan];
  706.           }
  707.  
  708.           /* multiply the volume by 4 and add 8 to center around 128 */
  709.           /* NOTE: this statement could be eliminated for efficiency, */
  710.           /* though the volume would be lower. */
  711.           cur_val = (cur_val << 2) + 8;
  712.           
  713.           /* add the current value to the output buffer */
  714.           *buffer++ = cur_val;
  715.           
  716.           /* and indicate one less byte in the buffer */
  717.           n--;          
  718.        }
  719.     }
  720. #endif
  721. }      
  722.  
  723.                               
  724. /*****************************************************************************/
  725. /* Module:  Pokey_process()                                                  */
  726. /* Purpose: To fill the output buffer with the sound output based on the     */
  727. /*          pokey chip parameters.  This routine has not been optimized.     */
  728. /*          Though it is not used by the program, I've left it for reference.*/
  729. /*                                                                           */
  730. /* Author:  Ron Fries                                                        */
  731. /* Date:    September 22, 1996                                               */
  732. /*                                                                           */
  733. /* Inputs:  *buffer - pointer to the buffer where the audio output will      */
  734. /*                    be placed                                              */
  735. /*          n - size of the playback buffer                                  */
  736. /*                                                                           */
  737. /* Outputs: the buffer will be filled with n bytes of audio - no return val  */
  738. /*                                                                           */
  739. /*****************************************************************************/
  740.  
  741. void Pokey_process (register unsigned char *buffer, register UWORD n)
  742. {
  743. #ifdef VOXWARE
  744.  
  745.     register ULONG *div_n_ptr;
  746.     register ULONG *samp_cnt_w_ptr;
  747.     register ULONG event_min;
  748.     register UBYTE next_event;
  749.     register UBYTE cur_val;
  750.     register UBYTE *out_ptr;
  751.     register UBYTE audc;
  752.     register UBYTE toggle;
  753.  
  754.  
  755.     /* set a pointer to the whole portion of the samp_n_cnt */
  756.     samp_cnt_w_ptr = (ULONG *)((UBYTE *)(&Samp_n_cnt[0])+1);
  757.    
  758.     /* set a pointer for optimization */
  759.     out_ptr = Outvol;
  760.  
  761.     /* The current output is pre-determined and then adjusted based on each */
  762.     /* output change for increased performance (less over-all math). */
  763.     /* add the output values of all 4 channels */
  764.     cur_val  = 2;                 /* start with a small offset */
  765.     cur_val += *out_ptr++;
  766.     cur_val += *out_ptr++;
  767.     cur_val += *out_ptr++;
  768.     cur_val += *out_ptr++;
  769.  
  770.     /* loop until the buffer is filled */
  771.     while (n)
  772.     {
  773.        /* Normally the routine would simply decrement the 'div by N' */
  774.        /* counters and react when they reach zero.  Since we normally */
  775.        /* won't be processing except once every 80 or so counts, */
  776.        /* I've optimized by finding the smallest count and then */
  777.        /* 'accelerated' time by adjusting all pointers by that amount. */
  778.  
  779.        /* find next smallest event (either sample or chan 1-4) */
  780.        next_event = SAMPLE;
  781.        event_min = *samp_cnt_w_ptr;
  782.  
  783.        /* Though I could have used a loop here, this is faster */
  784.        div_n_ptr = Div_n_cnt;
  785.        if (*div_n_ptr <= event_min)
  786.        {
  787.           event_min = *div_n_ptr;
  788.           next_event = CHAN1;
  789.        }
  790.        div_n_ptr++;
  791.        if (*div_n_ptr <= event_min)
  792.        {
  793.           event_min = *div_n_ptr;
  794.           next_event = CHAN2;
  795.        }
  796.        div_n_ptr++;
  797.        if (*div_n_ptr <= event_min)
  798.        {
  799.           event_min = *div_n_ptr;
  800.           next_event = CHAN3;
  801.        }
  802.        div_n_ptr++;
  803.        if (*div_n_ptr <= event_min)
  804.        {
  805.           event_min = *div_n_ptr;
  806.           next_event = CHAN4;
  807.        }
  808.  
  809.        /* decrement all counters by the smallest count found */
  810.        /* again, no loop for efficiency */
  811.        *div_n_ptr -= event_min;
  812.        div_n_ptr--;
  813.        *div_n_ptr -= event_min;
  814.        div_n_ptr--;
  815.        *div_n_ptr -= event_min;
  816.        div_n_ptr--;
  817.        *div_n_ptr -= event_min;
  818.  
  819.        *samp_cnt_w_ptr -= event_min;
  820.  
  821.        /* since the polynomials require a mod (%) function which is 
  822.           division, I don't adjust the polynomials on the SAMPLE events,
  823.           only the CHAN events.  I have to keep track of the change,
  824.           though. */
  825.        Poly_adjust += event_min;
  826.  
  827.        /* if the next event is a channel change */
  828.        if (next_event != SAMPLE)
  829.        {
  830.           /* shift the polynomial counters */
  831.           P4  = (P4  + Poly_adjust) % POLY4_SIZE;
  832.           P5  = (P5  + Poly_adjust) % POLY5_SIZE;
  833.           P17 = (P17 + Poly_adjust) % Poly17_size;
  834.          
  835.           /* reset the polynomial adjust counter to zero */
  836.           Poly_adjust = 0;
  837.  
  838.           /* adjust channel counter */
  839.           Div_n_cnt[next_event] += Div_n_max[next_event];
  840.  
  841.           /* get the current AUDC into a register (for optimization) */
  842.           audc = AUDC[next_event];
  843.  
  844.           /* set a pointer to the current output (for opt...) */
  845.           out_ptr = &Outvol[next_event];
  846.  
  847.           /* assume no changes to the output */
  848.           toggle = FALSE;
  849.  
  850.           /* From here, a good understanding of the hardware is required */
  851.           /* to understand what is happening.  I won't be able to provide */
  852.           /* much description to explain it here. */
  853.  
  854.           /* if the output is pure or the output is poly5 and the poly5 bit */
  855.           /* is set */
  856.           if ((audc & NOTPOLY5) || bit5[P5])
  857.           {
  858.              /* if the PURE bit is set */
  859.              if (audc & PURE)
  860.              {               
  861.                 /* then simply toggle the output */
  862.                 toggle = TRUE;
  863.              }
  864.              /* otherwise if POLY4 is selected */
  865.              else if (audc & POLY4)
  866.              {
  867.                 /* then compare to the poly4 bit */
  868.                 toggle = (bit4[P4] == !(*out_ptr));
  869.              }
  870.              else
  871.              {
  872.                 /* otherwise compare to the poly17 bit */
  873.                 toggle = (bit17[P17] == !(*out_ptr));
  874.              }
  875.           }
  876.  
  877.           /* At this point I haven't emulated the filters.  Though I don't
  878.              expect it to be complicated, I don't believe this feature is
  879.              used much anyway.  I'll work on it later. */
  880.           if ((next_event == CHAN1) || (next_event == CHAN3))
  881.           {
  882.              /* INSERT FILTER HERE */
  883.           }
  884.  
  885.           /* if the current output bit has changed */
  886.           if (toggle)
  887.           {
  888.              if (*out_ptr)
  889.              {
  890.                 /* remove this channel from the signal */
  891.                 cur_val -= *out_ptr;
  892.                 
  893.                 /* and turn the output off */
  894.                 *out_ptr = 0;
  895.              }
  896.              else
  897.              {
  898.                 /* turn the output on */
  899.                 *out_ptr = audc & VOLUME_MASK;
  900.  
  901.                 /* and add it to the output signal */
  902.                 cur_val += *out_ptr;
  903.              }
  904.           }
  905.        }
  906.        else /* otherwise we're processing a sample */
  907.        {
  908.           /* adjust the sample counter - note we're using the 24.8 integer
  909.              which includes an 8 bit fraction for accuracy */
  910.           *Samp_n_cnt += Samp_n_max;
  911.  
  912.           /* add the current value to the output buffer */
  913.           *buffer++ = cur_val << 2;
  914.           
  915.           /* and indicate one less byte in the buffer */
  916.           n--;          
  917.        }
  918.     }
  919. #endif
  920. }                                    
  921.       
  922. /***************************************************************************
  923.  ** Generate POKEY Timer IRQs if required                                 **
  924.  ** called on a per-scanline basis, not very precise, but good enough     **
  925.  ** for most applications                                                 **
  926.  ***************************************************************************/
  927.  
  928. void POKEY_Scanline(void)
  929. {
  930.  
  931.   if (DELAYED_SERIN_IRQ > 0) {
  932.     if (--DELAYED_SERIN_IRQ == 0 ) {
  933.       IRQST &= 0xdf;
  934.       if (IRQEN & 0x20) 
  935.     GenerateIRQ();
  936.       /* else printf("SerIn missing.\n"); */
  937.     } 
  938.   }
  939.  
  940.   if (DELAYED_SEROUT_IRQ > 0) {
  941.     if (--DELAYED_SEROUT_IRQ == 0 ) {
  942.       IRQST &= 0xef;
  943.       if (IRQEN & 0x10)
  944.     GenerateIRQ();
  945.       /* else printf("SerOut missing.\n"); */
  946.       DELAYED_XMTDONE_IRQ += XMTDONE_INTERVAL;
  947.     } 
  948.   }
  949.  
  950.   if (DELAYED_XMTDONE_IRQ > 0) {
  951.     if (--DELAYED_XMTDONE_IRQ == 0) {
  952.       IRQST &= 0xf7;
  953.       if (IRQEN & 0x08)
  954.     GenerateIRQ(); 
  955.       /* else printf("XMTDone missing.\n"); */
  956.     } 
  957.   }
  958.  
  959. /* one scanline is 15Khz for an ordinary TV */
  960.  
  961.   if ((Div_n_irq[CHAN1] += DIV_15)>Div_n_max[CHAN1]) {
  962.     Div_n_irq[CHAN1] = 0;      
  963.     if (IRQEN & 0x01) {
  964.       IRQST &= 0xfe;
  965.       GenerateIRQ();
  966.     }
  967.   }
  968.  
  969.   if ((Div_n_irq[CHAN2] += DIV_15)>Div_n_max[CHAN2]) {
  970.     Div_n_irq[CHAN2] = 0;
  971.     if (IRQEN & 0x02) {
  972.       IRQST &= 0xfd;
  973.       GenerateIRQ();
  974.     }
  975.   }
  976.  
  977.   if ((Div_n_irq[CHAN3] += DIV_15)>Div_n_max[CHAN3]) {
  978.     Div_n_irq[CHAN3] = 0;    
  979.   }
  980.  
  981.   if ((Div_n_irq[CHAN4] += DIV_15)>Div_n_max[CHAN4]) {
  982.     Div_n_irq[CHAN4] = 0;
  983.     if (IRQEN & 0x04) {
  984.       IRQST &= 0xfb;
  985.       GenerateIRQ();
  986.     }
  987.   }
  988.   
  989. }
  990.  
  991. void SendKey(UBYTE key)
  992. {
  993.   KBCODE = key;
  994.   IRQST  &= 0xbf;
  995.   if (IRQEN & 0x40)
  996.     GenerateIRQ();
  997. }
  998.  
  999. void SendBRK(void)
  1000. {
  1001.   IRQST &= 0x7f;
  1002.   if (IRQEN & 0x80)
  1003.     GenerateIRQ();
  1004. }
  1005.  
  1006.  
  1007.  
  1008.  
  1009.  
  1010.  
  1011.  
  1012.