home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / programs / emulaton / at2600 / !v2600 / c / tiasound < prev    next >
Text File  |  1997-03-24  |  23KB  |  613 lines

  1. /*****************************************************************************/
  2. /*                                                                           */
  3. /* Module:  TIA Chip Sound Simulator                                         */
  4. /* Purpose: To emulate the sound generation hardware of the Atari TIA chip.  */
  5. /* Author:  Ron Fries                                                        */
  6. /*                                                                           */
  7. /* Revision History:                                                         */
  8. /*    10-Sep-96 - V1.0 - Initial Release                                     */
  9. /*    14-Jan-97 - V1.1 - Cleaned up sound output by eliminating counter      */
  10. /*                       reset.                                              */
  11. /*                                                                           */
  12. /*****************************************************************************/
  13. /*                                                                           */
  14. /*                 License Information and Copyright Notice                  */
  15. /*                 ========================================                  */
  16. /*                                                                           */
  17. /* TiaSound is Copyright(c) 1996 by Ron Fries                                */
  18. /*                                                                           */
  19. /* This library is free software; you can redistribute it and/or modify it   */
  20. /* under the terms of version 2 of the GNU Library General Public License    */
  21. /* as published by the Free Software Foundation.                             */
  22. /*                                                                           */
  23. /* This library is distributed in the hope that it will be useful, but       */
  24. /* WITHOUT ANY WARRANTY; without even the implied warranty of                */
  25. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library */
  26. /* General Public License for more details.                                  */
  27. /* To obtain a copy of the GNU Library General Public License, write to the  */
  28. /* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */
  29. /*                                                                           */
  30. /* Any permitted reproduction of these routines, in whole or in part, must   */
  31. /* bear this legend.                                                         */
  32. /*                                                                           */
  33. /*****************************************************************************/
  34.  
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <time.h>
  38.  
  39.  
  40. /* define some data types to keep it platform independent */
  41. #ifdef WIN32
  42. #define int8  char
  43. #define int16 short
  44. #define int32 int
  45. #else
  46. #define int8  char
  47. #define int16 int
  48. #define int32 long
  49. #endif
  50.  
  51. #define uint8  unsigned int8 
  52. #define uint16 unsigned int16
  53. #define uint32 unsigned int32
  54.  
  55.  
  56. /* CONSTANT DEFINITIONS */
  57.  
  58. /* definitions for AUDCx (15, 16) */
  59. #define SET_TO_1     0x00      /* 0000 */
  60. #define POLY4        0x01      /* 0001 */
  61. #define DIV31_POLY4  0x02      /* 0010 */
  62. #define POLY5_POLY4  0x03      /* 0011 */
  63. #define PURE         0x04      /* 0100 */
  64. #define PURE2        0x05      /* 0101 */
  65. #define DIV31_PURE   0x06      /* 0110 */
  66. #define POLY5_2      0x07      /* 0111 */
  67. #define POLY9        0x08      /* 1000 */
  68. #define POLY5        0x09      /* 1001 */
  69. #define DIV31_POLY5  0x0a      /* 1010 */
  70. #define POLY5_POLY5  0x0b      /* 1011 */
  71. #define DIV3_PURE    0x0c      /* 1100 */
  72. #define DIV3_PURE2   0x0d      /* 1101 */
  73. #define DIV93_PURE   0x0e      /* 1110 */
  74. #define DIV3_POLY5   0x0f      /* 1111 */
  75.                  
  76. #define DIV3_MASK    0x0c                 
  77.                  
  78. #define AUDC0        0x15
  79. #define AUDC1        0x16
  80. #define AUDF0        0x17
  81. #define AUDF1        0x18
  82. #define AUDV0        0x19
  83. #define AUDV1        0x1a
  84.  
  85. /* the size (in entries) of the 4 polynomial tables */
  86. #define POLY4_SIZE  0x000f
  87. #define POLY5_SIZE  0x001f
  88. #define POLY9_SIZE  0x01ff
  89.  
  90. /* channel definitions */
  91. #define CHAN1       0
  92. #define CHAN2       1
  93.  
  94. #define FALSE       0
  95. #define TRUE        1
  96.  
  97.  
  98. /* LOCAL GLOBAL VARIABLE DEFINITIONS */
  99.  
  100. /* structures to hold the 6 tia sound control bytes */
  101. static uint8 AUDC[2];    /* AUDCx (15, 16) */
  102. static uint8 AUDF[2];    /* AUDFx (17, 18) */
  103. static uint8 AUDV[2];    /* AUDVx (19, 1A) */
  104.  
  105. static uint8 Outvol[2];  /* last output volume for each channel */
  106.  
  107.  
  108. /* Initialze the bit patterns for the polynomials. */
  109.  
  110. /* The 4bit and 5bit patterns are the identical ones used in the tia chip. */
  111. /* Though the patterns could be packed with 8 bits per byte, using only a */
  112. /* single bit per byte keeps the math simple, which is important for */
  113. /* efficient processing. */
  114.  
  115. static uint8 Bit4[POLY4_SIZE] =
  116.       { 1,1,0,1,1,1,0,0,0,0,1,0,1,0,0 };
  117.  
  118. static uint8 Bit5[POLY5_SIZE] =
  119.       { 0,0,1,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,0,1,1,1,0,1,0,1,0,0,0,0,1 };
  120.  
  121. /* I've treated the 'Div by 31' counter as another polynomial because of */
  122. /* the way it operates.  It does not have a 50% duty cycle, but instead */
  123. /* has a 13:18 ratio (of course, 13+18 = 31).  This could also be */
  124. /* implemented by using counters. */
  125.  
  126. static uint8 Div31[POLY5_SIZE] =
  127.       { 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 };
  128.  
  129. /* Rather than have a table with 511 entries, I use a random number */
  130. /* generator. */
  131.  
  132. static uint8 Bit9[POLY9_SIZE];
  133.  
  134. static uint8  P4[2]; /* Position pointer for the 4-bit POLY array */
  135. static uint8  P5[2]; /* Position pointer for the 5-bit POLY array */
  136. static uint16 P9[2]; /* Position pointer for the 9-bit POLY array */
  137.  
  138. static uint8 Div_n_cnt[2];  /* Divide by n counter. one for each channel */
  139. static uint8 Div_n_max[2];  /* Divide by n maximum, one for each channel */
  140.  
  141.  
  142. /* In my routines, I treat the sample output as another divide by N counter. */
  143. /* For better accuracy, the Samp_n_cnt has a fixed binary decimal point */
  144. /* which has 8 binary digits to the right of the decimal point. */
  145.  
  146. static uint16 Samp_n_max; /* Sample max, multiplied by 256 */
  147. static uint16 Samp_n_cnt; /* Sample cnt. */
  148.  
  149.  
  150.  
  151. /*****************************************************************************/
  152. /* Module:  Tia_sound_init()                                                 */
  153. /* Purpose: to handle the power-up initialization functions                  */
  154. /*          these functions should only be executed on a cold-restart        */
  155. /*                                                                           */
  156. /* Author:  Ron Fries                                                        */
  157. /* Date:    September 10, 1996                                               */
  158. /*                                                                           */
  159. /* Inputs:  sample_freq - the value for the '30 Khz' Tia audio clock         */
  160. /*          playback_freq - the playback frequency in samples per second     */
  161. /*                                                                           */
  162. /* Outputs: Adjusts local globals - no return value                          */
  163. /*                                                                           */
  164. /*****************************************************************************/
  165.  
  166. void Tia_sound_init (uint16 sample_freq, uint16 playback_freq)
  167. {
  168.    uint8 chan;
  169.    int16 n;
  170.  
  171.    /* fill the 9bit polynomial with random bits */
  172.    for (n=0; n<POLY9_SIZE; n++)
  173.    {
  174.       Bit9[n] = rand() & 0x01;       /* fill poly9 with random bits */
  175.    }
  176.  
  177.    /* calculate the sample 'divide by N' value based on the playback freq. */
  178.    Samp_n_max = (uint16)(((uint32)sample_freq<<8)/playback_freq);
  179.    Samp_n_cnt = 0;  /* initialize all bits of the sample counter */
  180.  
  181.    /* initialize the local globals */
  182.    for (chan = CHAN1; chan <= CHAN2; chan++)
  183.    {
  184.       Outvol[chan] = 0;
  185.       Div_n_cnt[chan] = 0;
  186.       Div_n_max[chan] = 0;
  187.       AUDC[chan] = 0;
  188.       AUDF[chan] = 0;
  189.       AUDV[chan] = 0;
  190.       P4[chan] = 0;
  191.       P5[chan] = 0;
  192.       P9[chan] = 0;
  193.    }
  194. }
  195.  
  196.  
  197. /*****************************************************************************/
  198. /* Module:  Update_tia_sound()                                               */
  199. /* Purpose: To process the latest control values stored in the AUDF, AUDC,   */
  200. /*          and AUDV registers.  It pre-calculates as much information as    */
  201. /*          possible for better performance.  This routine has not been      */
  202. /*          optimized.                                                       */
  203. /*                                                                           */
  204. /* Author:  Ron Fries                                                        */
  205. /* Date:    January 14, 1997                                                 */
  206. /*                                                                           */
  207. /* Inputs:  addr - the address of the parameter to be changed                */
  208. /*          val - the new value to be placed in the specified address        */
  209. /*                                                                           */
  210. /* Outputs: Adjusts local globals - no return value                          */
  211. /*                                                                           */
  212. /*****************************************************************************/
  213.  
  214. void Update_tia_sound (uint16 addr, uint8 val)
  215. {
  216.     uint16 new_val = 0;
  217.     uint8 chan;
  218.  
  219.     /* determine which address was changed */
  220.     switch (addr)
  221.     {
  222.        case AUDC0:
  223.           AUDC[0] = val & 0x0f;
  224.           chan = 0;
  225.           break;
  226.  
  227.        case AUDC1:
  228.           AUDC[1] = val & 0x0f;
  229.           chan = 1;
  230.           break;
  231.  
  232.        case AUDF0:
  233.           AUDF[0] = val & 0x1f;
  234.           chan = 0;
  235.           break;
  236.  
  237.        case AUDF1:
  238.           AUDF[1] = val & 0x1f;
  239.           chan = 1;
  240.           break;
  241.  
  242.        case AUDV0:
  243.           AUDV[0] = (val & 0x0f) << 3;
  244.           chan = 0;
  245.           break;
  246.  
  247.        case AUDV1:
  248.           AUDV[1] = (val & 0x0f) << 3;
  249.           chan = 1;
  250.           break;
  251.  
  252.        default:
  253.           chan = 255;
  254.           break;
  255.     }
  256.  
  257.     /* if the output value changed */
  258.     if (chan != 255)
  259.     {
  260.        /* an AUDC value of 0 is a special case */
  261.        if (AUDC[chan] == SET_TO_1)
  262.        {
  263.           /* indicate the clock is zero so no processing will occur */
  264.           new_val = 0;
  265.  
  266.           /* and set the output to the selected volume */
  267.           Outvol[chan] = AUDV[chan];
  268.        }
  269.        else
  270.        {
  271.           /* otherwise calculate the 'divide by N' value */
  272.           new_val = AUDF[chan] + 1;
  273.  
  274.           /* if bits 2 & 3 are set, then multiply the 'div by n' count by 3 */
  275.           if ((AUDC[chan] & DIV3_MASK) == DIV3_MASK)
  276.           {
  277.              new_val *= 3;
  278.           }
  279.        }
  280.  
  281.        /* only reset those channels that have changed */
  282.        if (new_val != Div_n_max[chan])
  283.        {
  284.           /* reset the divide by n counters */
  285.           Div_n_max[chan] = new_val;
  286.  
  287.           /* if the channel is now volume only or was volume only */
  288.           if ((Div_n_cnt[chan] == 0) || (new_val == 0))
  289.           {
  290.              /* reset the counter (otherwise let it complete the previous) */
  291.              Div_n_cnt[chan] = new_val;
  292.           }
  293.        }
  294.     }
  295. }
  296.  
  297.  
  298. /*****************************************************************************/
  299. /* Module:  Tia_process_2()                                                  */
  300. /* Purpose: To fill the output buffer with the sound output based on the     */
  301. /*          tia chip parameters.  This routine has not been optimized.       */
  302. /*          Though it is not used by the program, I've left it for reference.*/
  303. /*                                                                           */
  304. /* Author:  Ron Fries                                                        */
  305. /* Date:    September 10, 1996                                               */
  306. /*                                                                           */
  307. /* Inputs:  *buffer - pointer to the buffer where the audio output will      */
  308. /*                    be placed                                              */
  309. /*          n - size of the playback buffer                                  */
  310. /*                                                                           */
  311. /* Outputs: the buffer will be filled with n bytes of audio - no return val  */
  312. /*                                                                           */
  313. /*****************************************************************************/
  314.  
  315. void Tia_process_2 (register unsigned char *buffer, register uint16 n)
  316. {
  317.     register uint8 chan;
  318.  
  319.     /* loop until the buffer is filled */
  320.     while (n)
  321.     {
  322.        /* loop through the channels */
  323.        for (chan = CHAN1; chan <= CHAN2; chan++)
  324.        {
  325.           /* NOTE: this routine intentionally does not count down to zero */
  326.           /* since 0 is used as a special case - no clock */
  327.  
  328.           /* if the divide by N counter can count down */
  329.           if (Div_n_cnt[chan] > 1)
  330.           {
  331.              /* decrement and loop */
  332.              Div_n_cnt[chan]--;
  333.           }
  334.           /* otherwise if we've reached the bottom */
  335.           else if (Div_n_cnt[chan] == 1)
  336.           {
  337.              /* reset the counter */
  338.              Div_n_cnt[chan] = Div_n_max[chan];
  339.  
  340.              /* the P5 counter has multiple uses, so we inc it here */
  341.              P5[chan]++;
  342.              if (P5[chan] == POLY5_SIZE)
  343.                 P5[chan] = 0;
  344.  
  345.              /* check clock modifier for clock tick */
  346.  
  347.              /* if we're using pure tones OR
  348.                    we're using DIV31 and the DIV31 bit is set OR
  349.                    we're using POLY5 and the POLY5 bit is set */
  350.              if  (((AUDC[chan] & 0x02) == 0) ||
  351.                  (((AUDC[chan] & 0x01) == 0) && Div31[P5[chan]]) ||
  352.                  (((AUDC[chan] & 0x01) == 1) &&  Bit5[P5[chan]]))
  353.              {
  354.                 if (AUDC[chan] & 0x04)       /* pure modified clock selected */
  355.                 {
  356.                    if (Outvol[chan])         /* if the output was set */
  357.                       Outvol[chan] = 0;      /* turn it off */
  358.                    else
  359.                       Outvol[chan] = AUDV[chan];   /* else turn it on */
  360.                 }
  361.                 else if (AUDC[chan] & 0x08)  /* check for p5/p9 */
  362.                 {
  363.                    if (AUDC[chan] == POLY9)  /* check for poly9 */
  364.                    {
  365.                       /* inc the poly9 counter */
  366.                       P9[chan]++;
  367.                       if (P9[chan] == POLY9_SIZE)
  368.                          P9[chan] = 0;
  369.  
  370.                       if (Bit9[P9[chan]])    /* if poly9 bit is set */
  371.                          Outvol[chan] = AUDV[chan];
  372.                       else
  373.                          Outvol[chan] = 0;
  374.                    }
  375.                    else                      /* must be poly5 */
  376.                    {
  377.                       if (Bit5[P5[chan]])
  378.                          Outvol[chan] = AUDV[chan];
  379.                       else
  380.                          Outvol[chan] = 0;
  381.                    }
  382.                 }
  383.                 else  /* poly4 is the only remaining option */
  384.                 {
  385.                    /* inc the poly4 counter */
  386.                    P4[chan]++;
  387.                    if (P4[chan] == POLY4_SIZE)
  388.                       P4[chan] = 0;
  389.  
  390.                    if (Bit4[P4[chan]])
  391.                       Outvol[chan] = AUDV[chan];
  392.                    else
  393.                       Outvol[chan] = 0;
  394.                 }
  395.              }
  396.           }
  397.        }
  398.  
  399.        /* decrement the sample counter - value is 256 since the lower
  400.           byte contains the fractional part */
  401.        Samp_n_cnt -= 256;
  402.  
  403.        /* if the count down has reached zero */
  404.        if (Samp_n_cnt < 256)
  405.        {
  406.           /* adjust the sample counter */
  407.           Samp_n_cnt += Samp_n_max;
  408.  
  409.           /* calculate the latest output value and place in buffer */
  410.           *(buffer++) = Outvol[0] + Outvol[1];
  411.  
  412.           /* and indicate one less byte to process */
  413.           n--;
  414.        }
  415.     }
  416. }
  417.  
  418.  
  419. /*****************************************************************************/
  420. /* Module:  Tia_process()                                                    */
  421. /* Purpose: To fill the output buffer with the sound output based on the     */
  422. /*          tia chip parameters.  This routine has been optimized.           */
  423. /*                                                                           */
  424. /* Author:  Ron Fries                                                        */
  425. /* Date:    September 10, 1996                                               */
  426. /*                                                                           */
  427. /* Inputs:  *buffer - pointer to the buffer where the audio output will      */
  428. /*                    be placed                                              */
  429. /*          n - size of the playback buffer                                  */
  430. /*                                                                           */
  431. /* Outputs: the buffer will be filled with n bytes of audio - no return val  */
  432. /*                                                                           */
  433. /*****************************************************************************/
  434.  
  435. void Tia_process (register unsigned char *buffer, register uint16 n)
  436. {
  437.     register uint8 audc0,audv0,audc1,audv1;
  438.     register uint8 div_n_cnt0,div_n_cnt1;
  439.     register uint8 p5_0, p5_1,outvol_0,outvol_1;
  440.  
  441.     audc0 = AUDC[0];
  442.     audv0 = AUDV[0];
  443.     audc1 = AUDC[1];
  444.     audv1 = AUDV[1];
  445.  
  446.     /* make temporary local copy */
  447.     p5_0 = P5[0];
  448.     p5_1 = P5[1];
  449.     outvol_0 = Outvol[0];
  450.     outvol_1 = Outvol[1];
  451.     div_n_cnt0 = Div_n_cnt[0];
  452.     div_n_cnt1 = Div_n_cnt[1];
  453.  
  454.     /* loop until the buffer is filled */
  455.     while (n)
  456.     {
  457.        /* Process channel 0 */
  458.        if (div_n_cnt0 > 1)
  459.        {
  460.           div_n_cnt0--;
  461.        }
  462.        else if (div_n_cnt0 == 1)
  463.        {
  464.           div_n_cnt0 = Div_n_max[0];
  465.  
  466.           /* the P5 counter has multiple uses, so we inc it here */
  467.           p5_0++;
  468.           if (p5_0 == POLY5_SIZE)
  469.              p5_0 = 0;
  470.  
  471.           /* check clock modifier for clock tick */
  472.           if  (((audc0 & 0x02) == 0) ||
  473.               (((audc0 & 0x01) == 0) && Div31[p5_0]) ||
  474.               (((audc0 & 0x01) == 1) &&  Bit5[p5_0]))
  475.           {
  476.              if (audc0 & 0x04)       /* pure modified clock selected */
  477.              {
  478.                 if (outvol_0)        /* if the output was set */
  479.                    outvol_0 = 0;     /* turn it off */
  480.                 else
  481.                    outvol_0 = audv0; /* else turn it on */
  482.              }
  483.              else if (audc0 & 0x08)    /* check for p5/p9 */
  484.              {
  485.                 if (audc0 == POLY9)    /* check for poly9 */
  486.                 {
  487.                    /* inc the poly9 counter */
  488.                    P9[0]++;
  489.                    if (P9[0] == POLY9_SIZE)
  490.                       P9[0] = 0;
  491.  
  492.                    if (Bit9[P9[0]])
  493.                       outvol_0 = audv0;
  494.                    else
  495.                       outvol_0 = 0;
  496.                 }
  497.                 else                        /* must be poly5 */
  498.                 {
  499.                    if (Bit5[p5_0])
  500.                       outvol_0 = audv0;
  501.                    else
  502.                       outvol_0 = 0;
  503.                 }
  504.              }
  505.              else  /* poly4 is the only remaining option */
  506.              {
  507.                 /* inc the poly4 counter */
  508.                 P4[0]++;
  509.                 if (P4[0] == POLY4_SIZE)
  510.                    P4[0] = 0;
  511.  
  512.                 if (Bit4[P4[0]])
  513.                    outvol_0 = audv0;
  514.                 else
  515.                    outvol_0 = 0;
  516.              }
  517.           }
  518.        }
  519.  
  520.  
  521.        /* Process channel 1 */
  522.        if (div_n_cnt1 > 1)
  523.        {
  524.           div_n_cnt1--;
  525.        }
  526.        else if (div_n_cnt1 == 1)
  527.        {
  528.           div_n_cnt1 = Div_n_max[1];
  529.  
  530.           /* the P5 counter has multiple uses, so we inc it here */
  531.           p5_1++;
  532.           if (p5_1 == POLY5_SIZE)
  533.              p5_1 = 0;
  534.  
  535.           /* check clock modifier for clock tick */
  536.           if  (((audc1 & 0x02) == 0) ||
  537.               (((audc1 & 0x01) == 0) && Div31[p5_1]) ||
  538.               (((audc1 & 0x01) == 1) &&  Bit5[p5_1]))
  539.           {
  540.              if (audc1 & 0x04)       /* pure modified clock selected */
  541.              {
  542.                 if (outvol_1)        /* if the output was set */
  543.                    outvol_1 = 0;     /* turn it off */
  544.                 else
  545.                    outvol_1 = audv1; /* else turn it on */
  546.              }
  547.              else if (audc1 & 0x08)    /* check for p5/p9 */
  548.              {
  549.                 if (audc1 == POLY9)    /* check for poly9 */
  550.                 {
  551.                    /* inc the poly9 counter */
  552.                    P9[1]++;
  553.                    if (P9[1] == POLY9_SIZE)
  554.                       P9[1] = 0;
  555.  
  556.                    if (Bit9[P9[1]])
  557.                       outvol_1 = audv1;
  558.                    else
  559.                       outvol_1 = 0;
  560.                 }
  561.                 else                        /* must be poly5 */
  562.                 {
  563.                    if (Bit5[p5_1])
  564.                       outvol_1 = audv1;
  565.                    else
  566.                       outvol_1 = 0;
  567.                 }
  568.              }
  569.              else  /* poly4 is the only remaining option */
  570.              {
  571.                 /* inc the poly4 counter */
  572.                 P4[1]++;
  573.                 if (P4[1] == POLY4_SIZE)
  574.                    P4[1] = 0;
  575.  
  576.                 if (Bit4[P4[1]])
  577.                    outvol_1 = audv1;
  578.                 else
  579.                    outvol_1 = 0;
  580.              }
  581.           }
  582.        }
  583.  
  584.        /* decrement the sample counter - value is 256 since the lower
  585.           byte contains the fractional part */
  586.        Samp_n_cnt -= 256;
  587.  
  588.        /* if the count down has reached zero */
  589.        if (Samp_n_cnt < 256)
  590.        {
  591.           /* adjust the sample counter */
  592.           Samp_n_cnt += Samp_n_max;
  593.  
  594.           /* calculate the latest output value and place in buffer */
  595.           *(buffer++) = outvol_0 + outvol_1;
  596.  
  597.           /* and indicate one less byte to process */
  598.           n--;
  599.        }
  600.     }
  601.  
  602.     /* save for next round */
  603.     P5[0] = p5_0;
  604.     P5[1] = p5_1;
  605.     Outvol[0] = outvol_0;
  606.     Outvol[1] = outvol_1;
  607.     Div_n_cnt[0] = div_n_cnt0;
  608.     Div_n_cnt[1] = div_n_cnt1;
  609.  
  610. }
  611.  
  612.  
  613.