TMS9919 Sound chip

Internal structure
Timing diagram
Electrical characteristics

Programming the sound generators
Playing notes
Direct sound


The TMS9919 sound chip contains three independent tone generators and a noise generator that can emit either white noise (i.e. all frequency have identical energy) or periodic noise. I don't have the data manual for this chip, but I have one for the SN76489 and SN76496, very similar chips manufactured by TI. The only difference I noted was that the AUDIOIN pin is not connected on the SN76489AN. If anybody happens to have a copy of the actual TMS9919 manual please let me know.


      D2 |1 o  T    16| Vcc 
      D1 |2    M    15| D3 
      D0 |3    S    14| CLK 
   READY |4         13| D4 
     WE* |5    9    12| D5 
     CS* |6    9    11| D6 
AUDIOOUT |7    1    10| D7 
     Vss |8    9     9| AUDIOIN 
Power supply
Vcc +5V, (via a 6.8 uH inductor in the TI-99/4A)
Vss Ground

CPU interface
D0-D7 These input pins accept commands from the CPU.

CS* Chip select. When this pin is active (low) the TMS9919 will input data from the data bus. For proper operation, the device should be initialized by pulling both CS* and WE* high.

WE* Write enable. When active (low) this pin signals a write operation. As far as I know, all operations dealing with the TMS9919 are write operations. I'm not aware that there is anything to read. Anyone?

READY This pin goes low to put the CPU on hold until the TMS9919 is ready: it takes approximately 32 CLOCK cycles for the chip to load data into a register.

Sound pins
CLK Clock pin. Receives the basic clock signal used to generate sounds. The acceptable frequency ranges from 0 to 4MHz. On the TI-99/4A, this pin can receive either a 3.58 MHz signal from the VDP CPUCLK pin (pin 38), or a 447.4 kHz generated by the VDP GROMCLK pin (pin 37). The actual signal is selected via a jumper in the console. This was probably done so you could have either a SN76494N or a SN76489 as your sound chip. The SN76494N would use the 447.4 kHz and divide it by 2 internally, whereas the SN76489 would use the 3.58 MHz signal and divide it by 16 internally. The end result is the same in both cases: an internal clock signal of 223.7 kHz.

AUDIOIN This input pin receives preformed sound signals and transmits them to the AUDIOOUT pin. It is an analog input. In the TI-99/4A is is connected to pin #44 of the side port via a 330 Ohm resistor, for sound input from the speech synthesizer. It is also connected in parallel to the cassette input port which allow us to ear that funny noise when reading a program from tape. Finally, the TMS9901 also controls this line via a transistor, which could be used by application programs to directly generate sounds via the CRU. This pin is marked n.c. on the SN76489.

AUDIOOUT This pin carries the sound data to the monitor's speaker (pin 3 of the connector). It is connected to an internal analog audio amplifier.
 #7|--------+----||---+--uuu---+----< pin 3 monitor port
   |        |  100uF  | ?uH    | 
   |  0.1uF =    10nF =        = 10nF 
   |        |         |        | 
   |        +--www---Gnd      Gnd 
--+ 10 Ohm 

Internal structure

The signal received from the CLOCK pin is divided by 16 to provide the internal signal frequency. This means that the CLOCK signal can be as high as 4 MHz and yet produce audible sounds. Note that there exists a chip, SN76494N, that is exactly similar to the SN76489 except that the CLOCK signal is only divided by 2. It allows to use a clock signal in the 500 kHz range.

The chip contains three tone generators and a noise generator. Each tone generator consists in: a programmable frequency divider that divides the CLOCK frequency by a user-definable value to generate the appropriate tone, a fixed 1/2 frequency divider and a programmable attenuator that allows to control the volume in increments of 2 dB.

The noise generator comprises: a fixed 1/16 divider, a programmable divider (1/2, 1/4 or 1/8), a noise source and an attenuator identical to that of the tone generators. The programmable divider can also accept the output of tone generator number 3 as an input. The noise source is a shift register with a XOR feed-back to prevent lockup in zero state. It is possible to control this feedback circuit to toggle between a "white" noise and a periodic noise. The shift register is cleared each time the divider is loaded, then it shifts at the frequency determined by the divider output.

The four signals are combined by an analog summer, whose output drives an audio amplifier, typically with a current from 0 to -160 uA. The audio output can generate upto 10 mA.
                       ______      _____     __________
                   ,--| 1/N  |----| 1/2 |---|Attenuator|---,   +1.5V
          ______   |   ______      _____     __________    |     |  |\
CLOCK >--| 1/16 |--+--| 1/N  |----| 1/2 |---|Attenuator|-, '-|\  '--|+\
                   |   ______      _____     __________  '---| \    |  \_ _ AUDIOOUT
       ,-----------+--| 1/N  |----| 1/2 |-+-|Attenuator|-----|  \_ _|  / |
       |                  ,---------------'                  |  / | |-/  |
       |   ______         |        _____     __________   ,--| /  | |/   | 
       '--| 1/16 |----| 1/n  |----|shift|---|Attenuator|--'  |/   '--WWW-'
                                                           Summer    17K           

The four attenuators and the four programmable dividers can be accessed from the data bus, as 8 dedicated registers. The tone dividers are 10-bit wide and thus require two bytes of data.

Tone frequency dividers

R0 R1 R2 F6 F7 F8 F9 F0 F1 F2 F3 F4 F5

R0-R2: Register address (see below)
F0-F9: Number by which to divide the frequency (>01-3F)

NB The register address is latched on-chip when the first byte is passed. This means that the second byte can be sent repeatedly, as it is identified by a 0 in the most significant bit. In this way, you can very rapidly sweep frequencies, by changing only the 6 most significant bits (F0-F5) with a single byte transfer.

Noise frequency divider

R0 R1 R2 FB F0 F1

R0-R2: Register address (see below)
FB: Feed-back option 0 = periodic, 1 = white noise
F0-F1: Number by which to divide the frequency: 00 = 512, 01 = 1024, 10 = 2048, 11 = use generator #3


R0 R1 R2 A0 A1 A2 A3

R0-R2: Register address (see below)
A0-A3: Attenuation. A0 = 16 dB, A1 = 8 dB, A2 = 4dB, A3 = 2 dB. 1111 = sound off
The attenuation accuracy is quite poor: +/- 1 dB

Register address

R0 R1 R2 Register 
0 0 0 Tone 1 frequency divider 
0 0 1 Tone 1 attenuator
0 1 0 Tone 2 frequency divider 
0 1 1 Tone 2 attenuator
1 0 0 Tone 3 frequency divider 
1 0 1 Tone 3 attenuator
1 1 0 Noise frequency divider 
1 1 1 Noise attenuator

Timing diagram

______               _________               _______     
      \_____________/         \_____________/        CE*
_____|_a_| 90-150 ns                                 
     |   \___________/  >0     |  |a \        /      READY
     | >0   |                  |  |                  
            \_____________/    |  \_______     /     WE*     
        |>0|                   |                     
       X     first byte       X   second byte    X   D0-D7
a) 90-150 ns

Electrical characteristics

Absolute maximum ratings

Supply voltage: Vcc               7V
Input voltage:  AUDIOIN         0.9V
                All others        7V
Output current on AUDIOOUT     10 mA
Continuous power dissipation 1150 mW 
Free air temperature:     0 to 70 `C
Storage temperature:   -55 to 150 `C

Recommended operating conditions

Parameter Min Nom Max Unit
Supply voltage, Vcc 4.5 5 5.5 V
High-level input voltage 2 . . V
Low-level input voltage  . . 0.8 V
AUDIOIN input current 0 . 1.8 mA
High-level output voltage (READY)  . . 5.5 V
Low-level output current (READY) . . 2 mA
Input clock frequency . . 4 MHz
Free-air temperature 0 . 70 `C

Electrical characteristics under recommended conditions

Parameter Test conditions Min Typ Max Unit
High-level output current (READY)  Vo = +5.5V . . 10 uA
High-level input current (all digital pins) Vi = Vcc . . 10 uA
Low-level input current CE* pin
D0-D7, WE*, CLK pins
Vi = 0 . -25
Input bias voltage (AUDIOIN) R = 4.7 KOhm to Vcc 0.5 0.7 0.9 V
High-level output voltage (AUDIOOUT)  . . . 5.5 V
Low-level output voltage (READY)  I = 2 mA . 0.25 0.4 V
Peak-to-peak output voltage (AUDIOOUT)  Vcc = +5V Attenuation = 0 dB
(other generators -30 dB) 
260 . . mV
Supply current Outputs open . 30 50 mA
Input capacitance . . . 15 pF

Programming the sound generators

The four generators (3 tone and 1 noise) can be accessed independently by the data bus. The first byte of data contains the address of the desired generator and the parameter to change (frequency or volume). In some cases, a second byte of data may follow, that will be sent to the same generator as the previous one. In the TI-99/4A the sound chip data port is mapped at >8400, but the address is incompletely decoded: only A0-A5, A15 and MEMEN* are taken into account. Thus, the chip will respond to any even address in the range >8400->85FE.
Generator Frequency Volume
Tone 1 >8z >xy >9v
Tone 2 >Az >yx >Bv
Tone 2 >Cz >yx >Dv
Noise >En >Fv
Frequency = 111860.8 Hz              Volume v:  +1 = -2 dB (>F = off)


Two bytes are required to set the frequency of a tone generator. The first nibble of the first byte contains the address of the generator (>8, >A or >C). The second nibble should be appended to the end of the second byte to generate a 3-nibble number xyz. The output frequency can be calculated by dividing 111,860.8Hz by xyz. The value 111,860.8 is due to the fact that the 3.58 MHz clock signal is divided by 32 to produce the base frequency used by the generators.

Once the first byte is passed, the second byte can be modified as often as needed, as long as no other command is passed. This allows for rapid frequency changes, as only one byte needs to be passed (although only the 6 most-significant bits will be changed).


For the noise generator, only one byte is needed. The first nibble should contain the address (>E) and the second 3 command bits that decide whether the generator will emit white noise or periodic noise (bit 6) and select the basal frequency from a list of three. It is also possible to instruct the noise generator to adopt the same frequency as tone generator 3, even if the latter is currently silent (i.e. volume = >F).
1 1 1 0 0 w r r 
  >E      | | |
          | 0 0 : 6991 Hz 
          | 0 1 : 3496 Hz 
          | 1 0 : 1748 Hz 
          | 1 1 : freq of generator 3 
          0 : Periodic noise 
          1 : White noise


Strictly speaking, one does not set the volume for a generator, but rather its attenuation. That is, higher values result in lower volumes. Zero is the maximum volume, any increment by one reduces the volume by 2 dB (i.e. 100 times less sound energy), and >F turns the generator completely off.

Playing notes

Here is a table that you can use to program the frequencies of a "well-tempered keyboard". Just replace the dot with the code of the desired generator (>8, >A or >C) and pass the result as two bytes at >8400.
- .735 .C1A .60D .B06 .503 .B01
############ - .732 .419 .A0C .506 .203 .901
- .A2F .D17 .E0B .F05 .003 .801
############ - .F2C .816 .40B .A05 .D02  .601
- .72A .315 .A0A .505 .A02 .501
- .128 .014 .00A .005 .802 .401
############ - .D25 .E12 .709 .C04 .602 -
- .B23 .D11 .F08 .704 .402 -
############ - .B21 .D10 .708 .304 .202 -
.93F .C1F .E0F .F07 .004 .002 -
############ .03C .01E .00F .807 .C03 .E01 -
.A38 .51C .20E .107 .903 .C01 -

The underlined .E0F corresponds to the middle A at 440 Hz. Note that many orchestra nowadays tend to tune their middle A at a higher pitch: at 441, 442 or even upto 444 Hz. I'll leave you with the task to correct this table accordingly..

You may have noted that the calculated frequency follows a log scale, dobbling from one column to another (taking rounding mistakes into account). That's because of the way our ear is designed: octaves, subjectively "equal" intervals of 12 half-tones correspond to a dobbling of the frequency. This allow us to ear a wide range of frequencies.

One last remark: this table works well to emulate keyboard instruments (piano, harpsichord, organ) that are "tempered", i.e. on which an A sharp is the same as a B flat. This is not the case for other instruments like the violin or the cello: on these the A sharp is a tad (a "coma" in french, a "microtone" in english?) higher than the B flat. Most people won't notice the difference, unless the same note is played on a piano and a violin together: it gives the impression that the violinist does not play in tune. He does! It's the piano that's wrong.


* Let's play a note 
       LI   R0,>8400     Sound port address on the TI-99/4A 
       LI   R1,>8E0F     Middle A on generator 1 
       MOVB R1,*R0 
       SWPB R1 
       MOVB R1,*R0 
       LI   R2,>9200     Volume: 4 dB below maximum 
       MOVB R2,*R0       Play it
       ...               Wait
* Now let's make a noise (the note is still playing) 
       LI   R1,>DF00     Make sure generator 3 is off 
       MOVB R1,*R0 
       LI   R1,>CC1A     C on generator 3 
       MOVB R1,*R0 
       SWPB R1 
       MOVB R1,*R0 
       LI   R1,>E300     Periodic noise, picking frequency from gen 3 
       MOVB R1,*R0 
       LI   R1,>F000     Volume: full blast
       ...               Wait 

* Turn all sounds off 
       LI   R1,>9F00     Start with generator 1 
LP1    MOVB R1,*R0       Turn it off 
       AI   R1,>2000     Next generator 
       JNC  LP1          Carry set when >EF becomes >00
       B    *R11

This example is deceptively simple: programming music is a fairly complicated task. First you must decide how to encode your music: do you want a separate list for each generator or a common list?

Then you must time each note. A good way is to place a sound list in the VDP memory and to let the ISR play it, but according to your needs you may want to do it yourself, for instance with the TMS9901 timer. You must also remember that each note should be followed by a small silence, unless you're playing legato (although to repeat a note in legato, you still need a small silence). Conversely, to play staccato or pizzicatti you must reduce the duration of a note and increase the silence accordingly.

And then, there is the problem of the volume: progressive changes in volume (crescendo, decrescendo) can be tricky to program as they must be integrated into your sound list. Finally for some instruments to sound natural, the sound of each note should be slowly fading over time. That's the case with the piano for instance (but not with the flute: as long as the musician is blowing steadily, the volume remains unchanged).

Direct sound

We can send sound directly to the speaker via the sound chip, without using the generators. This is achieved with CRU bit 24 in the console: it is normally used to control whether the input from a cassette tape recorder will be audible, but thanks to a pull-up resistor it can also be used to generate sound even if no recorder is installed.
* Tentative routine to program direct sound via the CRU
* R1 contains a pointer to a list of sound bits
* R2 is the size of the list, in words
* R3 is the delay between two bits (i.e. depends on the sampling rate)
* In addition, the routine makes use of R4, R10 and R12. 
       CLR  R12         CRU base of the TMS9901 
LP2    MOV  *R1+,R4     Get one word from the list 
       LI   R0,16       16 bits per word 
LP1    SLA  R4,1        Test next bit 
       JNC  SK1 
       SBO  24          Send 1 to sound gate 
       JMP  SK2 
SK1    SBZ  24          Send 0 to sound gate 
SK2    BL   @DELAY      Delay between two bits
       DEC  R0 
       JNE  LP1         Next bit
       DEC  R2 
       JNE  LP2         Next word
       B    *R10
* Delay routine
DELAY MOV  R3,R12      Get delay value (in R12, to save a register)
LP3   DEC  R12
      JNE  LP3         Keep waiting
      B    *R11        R12 is now >0000, which is the correct CRU value
* NB: for short delays, we should account for the longer time between two
* words, due to the 4 extra instructions needed to load a new word.
* Main program
START LI   R1,BUFFER   Buffer address
      LI   R2,>0800    Buffer size
      LI   R3,>AAAA    Test pattern: highest possible pitch (1010 1010)
L0    MOV  R3,*R1+     Fill buffer with test pattern
      DEC  R2
      JNE  L0
      LI   R1,BUFFER   Buffer address
      LI   R2,>0800    Buffer size
      LI   R3,>0040    Delay value
      BL   @BITSND     Play buffer content
      ...              Return when done (this may take time)

Here, the tricky part is to determine the list of bits to be passed. I wonder if PC .RAW files could be used?

Also, I don't think there is any way to control the volume. Any suggestions?


A different method was used by Barry Boone in his excellent SoundFX program. He sets the maximum frequency (>001) on the three sound generators and then modulates the volume (identically for all three). Obviously, this implies carefully controlled timing loops so as to generate the required frequency.

Barry made the SoundFX source available on his website, so I encourage you to have a look at it. Here is an excerpt, containing only the sound generation routines and the routines that translate other sound files in SoundFX format.

Revision 1. 2/19/99. OK for release
Revision 2. 3/30/99. Polishing
Revision 3. 5/30/99. Tested & debugged examples
Revision 4. 6/16/00. Added SoundFX info
Revision 5. 7/2/00. Got the SN76489 manual. Added structure, timing, electricals.
Revision 6. 7/12/00. Got the SN76494 manual. Changes electricals.
Revision 7. 1/4/10. Swapped pin D3 and CLK. Added note of different clock signals from VDP.



Back to the TI-99/4A Tech Pages