FANCO-16 VERSION 3 SOUND CHIP REFERENCE ==================== Provisional edition October 2026 CONTENTS ======== 1. Introduction 2. Register map 3. Pitch 4. Waveforms 5. Envelopes 6. The filter 7. Volume and starting up 8. Timing of writes 9. Playing a note A. Differences from the real SID B. The host side 1. INTRODUCTION ================ The sound chip has three voices. Each voice has its own pitch, waveform and volume envelope. The voices can be sent through a shared filter. The chip is modeled on the SID of the Commodore 64 and has the same register layout, but it is a simpler design and does not sound exactly like a SID. Appendix A lists the differences. The chip's registers occupy addresses 40 to 5F of RAM. Write them with ordinary mov instructions. All music and sound effects are made by your program; the chip only plays what it is told. 2. REGISTER MAP ================ Voice registers --------------- Each voice has seven registers: Voice 1 Voice 2 Voice 3 Contents ------- ------- ------- ---------------- 40-41 47-48 4E-4F Frequency word 42-43 49-4A 50-51 Pulse width, 0-4095 44 4B 52 Control 45 4C 53 Attack, decay 46 4D 54 Sustain, release The control register: Bit Value Name Effect --- ----- -------- ------------------------ 0 01 gate 1 = play, 0 = release 1 02 sync Hard sync, see 4. 2 04 ring Ring modulation, see 4. 3 08 test Silences and holds the voice. 4 10 triangle Triangle wave 5 20 saw Sawtooth wave 6 40 pulse Pulse wave 7 80 noise Noise The attack and decay register holds attack in the high four bits and decay in the low four. The sustain and release register holds sustain in the high four bits and release in the low four. See section 5. Shared registers ---------------- Addr Contents ----- --------------------------------- 55-56 Filter cutoff, 0-2047. 55 holds the low three bits, 56 the high eight. 57 High four bits: resonance. Bits 0-2: send voice 1, 2 or 3 through the filter. 58 Low four bits: master volume. Bit 4: lowpass Bit 5: bandpass Bit 6: highpass Bit 7: silence voice 3, if it is not sent through the filter 59-5A Reserved 5B Bits 0-2: sine wave for voice 1, 2 or 3. Not on a real SID. 5C-5F Reserved Writes to reserved registers are accepted and do nothing. No register can be read back from the chip: reading one returns what you last wrote there. 3. PITCH ========= The frequency word sets the pitch: Hz = word * 985248 / 16777216 or, the other way round, word = Hz * 17.0284 (approximately) Note Hz Word Hex ---- ------- ----- ---- C4 261.63 4455 1167 A4 440.00 7493 1D45 C5 523.25 8910 22CE Each octave up doubles the word. 4. WAVEFORMS ============= Choose a waveform with bits 4 to 7 of the control register, or with the sine bits in 5B. - Triangle is soft, like a flute. - Sawtooth is bright and buzzy. - Pulse is hollow; its tone depends on the pulse width. The fraction of time the wave is high is width / 4096, so 2048 gives a square wave. - Noise is for drums, explosions and wind. Its pitch follows the frequency word. - Sine is the purest tone. If more than one waveform is chosen, they are averaged together. Sync restarts a voice each time the voice before it completes a cycle. Voice 1 follows voice 3, voice 2 follows voice 1 and voice 3 follows voice 2. Ring modulation mixes the triangle wave with the pitch of that same neighboring voice, giving bell-like sounds. The test bit silences the voice and holds it at the start of its wave. 5. ENVELOPES ============= Each voice has a volume envelope with four stages: /\ / \______ / \ A D S R Attack Setting gate to 1 starts the attack. The volume rises to full. Decay The volume falls to the sustain level. Sustain The volume stays there while gate is 1. Release Setting gate to 0 starts the release. The volume falls to zero. Sustain is a level from 0 to 15, where 15 is full volume. The other three are times, chosen from this table: Value Attack Decay, release ----- -------- -------------- 0 2 ms 6 ms 1 8 ms 24 ms 2 16 ms 48 ms 3 24 ms 72 ms 4 38 ms 114 ms 5 56 ms 168 ms 6 68 ms 204 ms 7 80 ms 240 ms 8 100 ms 300 ms 9 250 ms 750 ms A 500 ms 1.5 s B 800 ms 2.4 s C 1 s 3 s D 3 s 9 s E 5 s 15 s F 8 s 24 s Decay and release times are for a fall from full volume to zero. To play a note again, clear gate and then set it again. The attack starts from whatever the volume is at that moment. 6. THE FILTER ============== The filter can remove low or high frequencies, or keep only a band around the cutoff. 1. Choose which voices go through it, with bits 0-2 of 57. 2. Choose the kind of filter with bits 4-6 of 58. More than one may be on. 3. Set the cutoff in 55-56. 0 is about 30 Hz and 2047 about 12,000 Hz. 4. Set the resonance in the high four bits of 57. Higher values make the sound ring at the cutoff. Voices not sent through the filter are heard unchanged. 7. VOLUME AND STARTING UP ========================== The low four bits of 58 set the master volume of all three voices, from 0 (silent) to 15. When a program starts, every sound register is zero, except that a FAN0 program starts with the master volume at 15. A FAn0 program starts silent, but may turn the volume up later. The program image may also set sound registers directly; such bytes take effect from the start. Three loud voices together can be too loud and distort. Lower the master volume if they do. 8. TIMING OF WRITES ==================== A write to a sound register takes effect at the moment the instruction finishes, measured in processor cycles. The sound chip makes one sample every 2,500 cycles, so a write is heard from the next sample on. This is precise enough for fast arpeggios and drum effects. Every write counts, even one that stores the value already there. Writing the control register with gate still 1 does not restart a note. Virtual time stops while sys load is fetching a library, and the sound is silenced for that time. 9. PLAYING A NOTE ================== This plays the note A4 on voice 1, with a sawtooth wave and a short envelope: mov.w [0x40], 0x1D45 ; A4 mov.b [0x45], 0x09 ; attack 2 ms, ; decay 750 ms mov.b [0x46], 0x00 ; sustain 0, ; release 6 ms mov.b [0x44], 0x21 ; saw + gate on ... mov.b [0x44], 0x20 ; gate off The master volume is already 15 in a FAN0 program. In a FAn0 program, add mov.b [0x58], 15 APPENDIX A. DIFFERENCES FROM THE REAL SID ========================================== The chip is meant to feel familiar to SID programmers, not to reproduce a SID. It cannot play .sid files. In particular: - The sine wave in register 5B does not exist on a SID. On a SID, that address reads back voice 3's oscillator; here it cannot be read. - Envelopes are straight lines. The SID's curved decay and its timing quirks are not copied. - Mixed waveforms are averaged. The SID combines them in an unusual way that is not imitated. - The filter is an idealized digital filter, not a model of the SID's analog circuit. There is no volume-register "digi" trick. - Noise comes from a 23-bit shift register, but the output is formed differently. - Sync and ring modulation work on whole samples, not on single clock cycles. - Nothing is anti-aliased, so very high notes may sound rough. Pitch uses the same formula as a PAL SID, so note tables written for a PAL Commodore 64 can be used unchanged. APPENDIX B. THE HOST SIDE ========================== This appendix is for people changing the emulator, not for people writing programs. The synthesizer is sound.ts, shared with version 2. new SoundDevice(48000) makes one. write(offset, byte) sets a register, where offset is the address minus 40. render(count, events) returns count samples, applying each event { sampleOffset, register, value } before the sample it names. The runtime converts the cycle of each write to a sample offset by rounding up: offset = ceil((cycle - blockStart) / 2500) It renders blocks of 400 samples, which is 1,000,000 cycles, and sends them to an AudioWorklet (audio-worklet.ts). The worklet resamples to the device rate, keeps at most half a second queued, and plays silence if the queue runs dry. It reports its queue length about every 20 ms. On an iPhone, Safari's Web Audio is silent while the phone's ringer switch is set to silent, unless the page asks for the "playback" audio session. The page does so when Run is pressed, where Safari supports it. Asking may pause other audio playing on the device.