Alley Cat Tandy Music Format
| Format type | Music |
|---|---|
| Notation type | Custom |
| Instruments | SN76496 |
| Max channel count | 3 |
| Max track count | Unknown |
| Max pattern count | Unknown |
| Max order count | Unknown |
| Tags? | None |
| Games |
The Tandy edition of Alley Cat stores a three-voice title tune in TANDYCAT.EXE. Separate byte lists supply notes and durations for each voice. The format and player differ from the IBM PC title tune.
File format
All offsets on this page are native Tandy DS offsets. Add 0x6940 to obtain a file offset; do not apply the IBM-to-Tandy address map. Words are little-endian.
| DS offset | Data type | Contents |
|---|---|---|
| 0x1014 | UINT16LE[] | Tone-divisor lookup data |
| 0x1231, 0x123A, 0x1243 | 9-byte voice records | Per-voice playback state and list pointers |
| 0x124C | UINT16LE[3] | Pointers to the three voice records |
| 0x1254 | UINT16LE | Runtime arrangement pass, stepped by 2 |
| 0x1256 | UINT16LE[4] | Highest active voice offset per pass: 0, 2, 4, 4 |
The RE notes describe each voice record as countdown, attenuation, index word, channel bits, note-list pointer and duration-list pointer. The viewer directly decodes the two pointers as follows:
| Record-relative offset | Data type | Meaning |
|---|
The other fields are mutable player state; the viewer reconstructs countdown, attenuation and index in its own objects. At sequence index i, read notes[i] and durations[i]. There is no stored sequence count.
| Note byte | Meaning |
|---|---|
| 0x00 | Mute this voice |
| 0x86 | Reset this voice index to zero and fetch again; voice 0 also advances the arrangement pass by 2 |
| Other | Read a UINT16LE at DS:(0x1014 + note) and use its low 10 bits as the tone divisor |
As in the IBM tune, the note byte is a byte offset, not a word index. The parallel duration byte supplies the countdown. Validated playback should follow the decrement-before-fetch behaviour of tandyTune(); a zero duration is not documented as an end marker.
Playback
The player runs once per BIOS tick with PIT channel 0 programmed to CFFFh:
secondsPerTick = 53247 / 1193182 frequencyHz = 3579545 / (32 * divisor) (for a non-zero divisor)
This gives about 22.41 ticks per second. A new audible note sets attenuation to 3. On subsequent ticks while the note's countdown remains non-zero, attenuation increases by 2 until 0Fh (silent). A rest immediately mutes the voice.
Voice 0 is enabled on the first pass, voices 0–1 on the second and all three on the third and fourth. The arrangement table is indexed by (pass & 6) / 2; its values are compared against 2 * voiceNumber. The loop markers allow continued playback; the viewer chooses to reconstruct four passes rather than treating the fourth pass as an encoded end marker.
Notes
- The RE notes report 288 ticks per voice sequence, 1152 ticks for four passes, and an exact comparison of reconstructed audible divisors and attenuation against 4214 writes to port C0h over 1153 player ticks in DOSBox.
- The full Tandy game is not ported. This article describes the independently reconstructed title player and its tables, not a complete Tandy sound-effect decoder.
- The viewer guards reconstruction at 20000 ticks and limits consecutive loop-marker retries. Those are reader safeguards, not fields in the executable.
Source code
From re-alleycat, the open-source HTML5 port (revision b003aa63ffbb):
- viewer.html – tandyTune(), playTandy() and native Tandy pointers
- docs/RE_NOTES.md – Tandy player analysis, timing and chip-write validation
Credits
This file format was reverse engineered by VorticonCmdr. Please credit the original research when using this information in your own project, and include a link back to this wiki.