TIASOUND.C - TIA SOUND EMULATION V1.0 ===================================== As I'm sure you've already discovered, the Stella manual isn't always correct. My observations show what I believe to be several discrepancies in the description of the distortions. Of course, I could be wrong on a few of these, so if some of the games don't sound right, please let me know which ones. If possible, it would be best if you could send me a wave file of what it is supposed to sound like, preferably at 44 KHz. Only a few seconds should be necessary. TIA AUDIO CIRCUITRY =================== THE HARDWARE ------------ In general, the sound hardware can be described as follows: Selecting the Clock Modifier - Bits D0 and D1 --------------------------------------------- Bits D0 and D1 select the output clock modifier: D1 D0 ------- 0 0 - direct clock (pure) 0 1 - direct clock (pure) 1 0 - divide by 31 1 1 - 5-bit polynomial The 'divide by 31' isn't simply the input clock divided by 31. It is, in essence, a 5-bit polynomial with only two bits set. The resulting square wave actually has a 13:18 ratio. This may be implemented in the hardware as a pair of traps on a 5-bit counter. Selecting the Source Pattern - Bits D2 and D3 --------------------------------------------- Bits D2 and D3 select the source to be clocked: D3 D2 ------- 0 0 - 4-bit polynomial 0 1 - pure (Q') 1 0 - 5-bit polynomial 1 1 - pure (Q') The 'pure' tones are generated by toggling the output. Whenever a clock tick is received, the output will change states. I've used the notation Q' to indicate the 'logical NOT of the last output'. Note that since the output toggles, this can be thought of as a divide by 2 since the output frequency will be half of the input frequency. This is only true for the pure tones. Selecting the Source Clock - Bits D2 and D3 ------------------------------------------- When bits D2 and D3 are both set, it affects the source clock. I believe the '30KHz' clock is actually the 3.58MHz clock divided by 114. When bits D2 and D3 are set, the input source is switched to the 1.19MHz clock, so the '30KHz' source clock is reduced to approximately 10KHz. Exceptions - Selecting No Output or the 9-bit Polynomial -------------------------------------------------------- There are two exceptions that occur when bits D0-D2 are all 0. If AUDC is zero (0000), then I believe the output is set equal to the volume. If AUDC is equal to 8 (1000), the 9-bit polynomial is selected as the source to be clocked. Updated Detailed Functions for AUDC ----------------------------------- From my observations, I would describe the distortion selections as follows: HEX D3 D2 D1 D0 Clock Source Clock Modifier Source Pattern --- ------------- -------------- ---------------- ---------------- 0 0 0 0 0 3.58 MHz/114 -> none (pure) -> none 1 0 0 0 1 3.58 MHz/114 -> none (pure) -> 4-bit poly 2 0 0 1 0 3.58 MHz/114 -> divide by 31 -> 4-bit poly 3 0 0 1 1 3.58 MHz/114 -> 5-bit poly -> 4-bit poly 4 0 1 0 0 3.58 MHz/114 -> none (pure) -> pure (~Q) 5 0 1 0 1 3.58 MHz/114 -> none (pure) -> pure (~Q) 6 0 1 1 0 3.58 MHz/114 -> divide by 31 -> pure (~Q) 7 0 1 1 1 3.58 MHz/114 -> 5-bit poly -> pure (~Q) 8 1 0 0 0 3.58 MHz/114 -> none (pure) -> 9-bit poly 9 1 0 0 1 3.58 MHz/114 -> none (pure) -> 5-bit poly A 1 0 1 0 3.58 MHz/114 -> divide by 31 -> 5-bit poly B 1 0 1 1 3.58 MHz/114 -> 5-bit poly -> 5-bit poly C 1 1 0 0 1.19 MHz/114 -> none (pure) -> pure (~Q) D 1 1 0 1 1.19 MHz/114 -> none (pure) -> pure (~Q) E 1 1 1 0 1.19 MHz/114 -> divide by 31 -> pure (~Q) F 1 1 1 1 1.19 MHz/114 -> 5-bit poly -> pure (~Q) For the most part, this follows the Stella manual, but there are a few differences. Probably the most notable are hex entries 'A' and 'B', which are listed in the Stella manual as 'div 31: pure tone' and 'set last 4 bits to 1'. On entries 'A' and 'B', both the data source and the clock have the same number of entries (31). Because of this, they will always align in the same way. Entry 'A' will then reduce to a pure 'div by 31' output which is identical to entry '6'. On 'B', both the source and the clock align in such a way that the output will always be 1. THE POLYNOMIALS --------------- The 4-bit, 5-bit, and 9-bit polynomials are essentially tables containing a random series of bits (they are implemented in hardware as shift registers). Because the tables are fixed in length, the 'random' pattern will repeat periodically. The size of the table is described by its name. The actual size of the table is 2^x - 1, where x is either the 4, 5 or 9. The 4-bit polynomial has 15 entries, the 5-bit polynomial has 31 entries, and the 9-bit polynomial has 511 entries. I've performed some analysis on the output of the actual Atari 2600, and believe I have the actual 4-bit and 5-bit polynomials used by the Atari. These have been encoded as byte arrays in my routines. For the 9-bit polynomial, I use a random number generator which should produce approximately the same results. THE CLOCK --------- I believe the input clock for the audio is a division of the main system clock. With this assumption, I determined that the input clock for the audio is equal to the 3.58MHz system clock divided by 114. Note that this produces an actual audio clock of 31.4 KHz. This value closely matches the frequencies I recorded from my unit. The Stella manual describes the Audio Clock as approximately 30KHz, which I suppose is correct if you consider 5% to be approximate. If both bits D2 and D3 of the AUDC register are set, I believe the TIA chip uses the 1.19MHz clock for the base audio clock instead of the 3.58MHz. This, of course, produces the 'divide by 3' functionality described in the Stella manual. TIASOUND.C ========== The TIASOUND.C file is the heart of the TIA Sound Emulation program. Although the routines in the file must work together, no other files are modules are required for operation. A header file, 'TIASOUND.H', has been included for use in other modules, and provides the necessary function prototypes. I've attempted to make the routines as portable as possible, so the file should compile on almost any compiler with little or no modification. I have made some attempts at optimizing the routines, though I am sure more optimization can be done. They are currently only available in 'C'. I'll be happy to convert them to assembly language if desired. Please feel free to send me e-mail (see below). The routines are easy to use. Detailed descriptions on the function calls are listed below. GENERAL OVERVIEW ---------------- On start-up of the system, a single call should be made to Tia_sound_init. This routine will prepare the structures for sound output. This routine can be called again if necessary during warm-start or other reset. Once in the main loop, there are two other functions that will be used. Whenever the system needs to write to either the AUDC, AUDV or AUDF values, a call should be made to the Update_tia_sound routine. This routine will take care of updating the internal registers. It will pre-calculate several values to help with optimization. The only other routine that is called is the Tia_process function. This function will fill a audio buffer with a specified number of bytes. This function should be called whenever a new audio buffer is required. For best results, I recommend using at least two output buffers. Using this scheme, the sound card can be playing one buffer while the system is filling the other. DETAILED FUNCTION DESCRIPTIONS ------------------------------ Tia_sound_init(uint16 sample_freq, uint16 playback_freq) -------------------------------------------------------- This function initializes the structures used by the TiaSound.C routines. This function takes two parameters: the sample frequency and the playback frequency. The sample frequency is the frequency of the 30KHz source clock. For my calculations, this clock is about 31.4 KHz, though any 16-bit unsigned integer value can be used (1-65535). The playback frequency is the frequency of the sound playback (the frequency used by the sound card). For best results, both the playback frequency and the sample frequency should be identical. In the case where the sound card cannot support 31.4 KHz (i.e. the original SB and many 'SB compatible' cards), there are three options: 1) Set the sample frequency to 31400 and the playback frequency to the maximum possible (e.g. 22050). Though the system will reproduce all output values, a significant amount of aliasing is introduced. 2) Set the sample frequency and the playback frequency to the maximum possible (e.g. 22050). In this case, all output values are reproduced with no distortions; however, the pitch is about 2/3 of an octave low. 3) Set the sample frequency to 31400 and the playback frequency to exactly 1/2 of the sample frequency (15700). In this case, the output frequency is correct and the aliasing is minimized. The aliasing is only noticeable on the higher frequencies. Most notably, the highest pure tone (AUDF = 0) is inaudible. Feel free to experiment to find other alternatives as well. This function has no return value (void). Update_tia_sound (uint16 addr, uint8 val) ----------------------------------------- This function should be called each time an AUDC, AUDF or AUDV value changes. This function takes two parameters: the address to change and the new value. The address should be one of the following values: Addr Description ---- ----------- 0x15 AUDC0 0x16 AUDC1 0x17 AUDF0 0x18 AUDF1 0x19 AUDV0 0x1A AUDV1 Any values outside of this range will be ignored. The routine pre-calculates several values that are needed by the processing function. This is done to optimize performance. This function has no return value (void). Tia_process (unsigned char *buffer, uint16 n) --------------------------------------------- This function calculates and fills a buffer with unsigned 8-bit mono audio. This function takes two parameters: a pointer to the buffer to fill and the size of the buffer (limited to 65535). This function fills the buffer based on the requested size and returns. It automatically updates the pointers for the next call, so subsequent calls to this function will provide a continuous stream of data. The size of the buffer that is needed depends on the playback frequency. It is best to keep the buffer as small as possible to maximize response time to changes in the sound. Of course, the minimum size is dependent on system and emulator performance. Selecting the correct buffer size is a careful balance. Selecting a buffer size that is too small will produce noticeable clicks in the output, though selecting a size that is too large will cause a poor response time and possible delays in the system when the new buffer is filled. This function has no return value (void). License Information and Copyright Notice ======================================== TiaSound is Copyright(c) 1996 by Ron Fries This library is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU Library General Public License as published by the Free Software Foundation. This library 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 Library General Public License for more details. To obtain a copy of the GNU Library General Public License, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Any permitted reproduction of these routines, in whole or in part, must bear this legend.