SAP (Slight Atari Player) file format specification
A SAP file contains chip music of the Atari 8-bit computers.
History
The SAP format was created in the 1990s by Adam Bienias and was intended to be a single format for playback of any Atari 8-bit music on a PC. Adam Bienias has also created the first SAP player for Windows and later published its source code. Other players appeared later.
At the time of writing, there are five independent players of the SAP format:
- Slight Atari Player (SAP) by Adam Bienias
- Another Slight Atari Player (ASAP) by Piotr Fusik (me)
- Game_Music_Emu (GME) by Shay Green
- sapemu by Adrian Matoga
- Altirra by Avery Lee
There are many players for different platforms based on either SAP, ASAP or GME. sapemu runs on an Atari XL/XE computer with 128 KB RAM. Windows-only Altirra is a full emulator of Atari computers.
Concept
A SAP file contains the original data and code needed to playback the Atari music. SAP players actually run the program contained in the SAP file on an emulated or real (sapemu) 6502 processor. The program controls the POKEY chip, which generates the sound.
Same method is used with platforms other than Atari, for example the SID format for the C64 music.
Important advantages of SAP over, let's say, MP3, are that SAP files are very small (about 5 KB on average) and play more accurately as new players improve their emulation. The downside is that SAP files are generally hard to create. Creating SAP files from Atari software is called ripping and requires knowledge of the 6502 assembly language. On the other hand, Atari music in popular formats such as CMC or RMT can be easily converted to SAP (and back) using ASAP.
One SAP file may contain multiple independent tunes - these are called "subsongs". For example, several songs from one game may be ripped into one SAP file. Over 90% of SAP files contain just one song. Unfortunately, many audio players do not support multiple subsongs per file.
File Contents
A SAP file always consists of two parts: a plain-text header, followed by binary data. It is possible to create a SAP file by concatenating a text file with a binary file, for example:
On Windows:
copy /b music.txt+music.bin music.sap
On macOS or Linux:
cat music.txt music.bin >music.sap
Part One - Text Header
This part consists of tags, one tag per line. Lines should be terminated by a CR/LF (0x0d, 0x0a) pair. A line consists of an uppercase tag name and an optional argument, which might be a string, a decimal integer, a hexadecimal integer or a single letter. The argument should be separated from the tag name with a single space.
Example header:
SAP AUTHOR "Jakub Husak" NAME "Inside" DATE "1990" SONGS 3 TYPE B INIT 0F80 PLAYER 247F TIME 06:37.62 TIME 02:34.02 LOOP TIME 00:15.40 LOOP
The first line must consist of the word "SAP" immediately followed by CR/LF, for format identification.
It is recommended, but not required, that tags are specified in the order described below. Note that format identification in GStreamer requires the AUTHOR tag to be placed right after the "SAP" line.
The arguments to AUTHOR, NAME and DATE must be wrapped in doublequotes. Allowed are characters which are identical in ASCII and ATASCII (ATari ASCII), that is: characters with ASCII codes from space to underscore plus all lowercase letters, plus the pipe character (`|`). There are no backquote, tilde nor curly brackets in ATASCII. It is recommended to avoid doublequotes inside the arguments, as not all SAP players handle them. The arguments should be limited to 120 characters (plus the outer quotes).
It is strongly recommended that all SAP files contain
the AUTHOR, NAME and DATE tags.
Use "<?>"
for unknown values.
- AUTHOR
-
Name of the composer. The name should consist of a real name and optionally a nickname (scene handle, no scene group) in parentheses. If song was composed by many authors, separate them with " & ". Examples:
AUTHOR "Dariusz Duma (Dhor)" AUTHOR "Lukasz Sychowicz (X-Ray) & Piotr Swierszcz (Samurai)" AUTHOR "<?> (Trzcinowy Zakapior)" AUTHOR "Bill Williams <?>"
The last two examples are respecively: known nickname with an unknown real name and an uncertain author.
- NAME
-
Song title. Examples:
NAME "Jocky Wilson's Darts Challenge" NAME "<?>"
- DATE
-
Copyright year or year of creation. If exact date is known, it can be included in the DD/MM/YYYY format. Examples:
DATE "1986" DATE "1993-1994" DATE "28/08/1997" DATE "12/2001" DATE "23-26/07/2010" DATE "199?"
The last example represents some unknown year in the 1990s.
- SONGS
-
Number of subsongs in the file. If there is just one song in the file, it is recommended to omit this tag. ASAP currently limits the number of songs to 32.
- DEFSONG
-
Zero-based index of the subsong that should be played first when the file is opened. Defaults to zero.
- STEREO
-
Specifies that the file uses dual POKEY configuration. Takes no argument.
- NTSC
-
Specifies that the file should be played on an NTSC machine instead of the default PAL. Takes no argument. This tag is only supported on ASAP 2.1.1 and above.
- TYPE
-
Player type. The argument should be one uppercase letter: B, C, D or S. See the explanation below.
- FASTPLAY
-
Number of scanlines between calls of the player routine. A scanline is defined to be 114 Atari clock cycles. FASTPLAY defaults to one frame: 312 scanlines for PAL (about 50 Hz), 262 for NTSC (about 60 Hz). Most songs don't include this tag. Common values are 156 (twice per PAL frame), 104 (three times per frame) and 78 (four times per frame). ASAP 3.0.0 and above supports FASTPLAY up to 32767. Other SAP players may limit FASTPLAY to 312.
- INIT
-
Hexadecimal address of a 6502 routine that initializes the player. Required for player types B, D and S. Invalid for type C. The address should be specified as four uppercase hexadecimal digits, although players usually forgive lowercase and fewer digits.
- MUSIC
-
Hexadecimal address of the music data. Required for type C. Invalid for other types.
- PLAYER
-
Hexadecimal address of the player routine, called with constant frequency (see FASTPLAY).
- COVOX
-
Specifies that the file uses the COVOX hardware expansion at the specified hexadecimal address. COVOX offers better quality of digitalized sounds than the POKEY, in stereo. Currently only ASAP supports this and the only possible address is D600.
- TIME
-
Song duration in minutes, seconds and milliseconds. In files with subsongs, there is a separate TIME tag for every subsong. The optional LOOP modifier specifies that the song starts looping endlessly at the specified moment. Players can decide to play such songs longer. The exact format of the TIME argument is:
- one or two digits specifying minutes
- colon
- two digits specifying seconds
- optionally: decimal point (dot) followed by one to three digits (fraction of a second)
- optionally: one space followed by four uppercase letters "LOOP"
Part Two - Binary Data
This part contains the player routine and music data in the format of Atari executables. An Atari executable is a sequence of one or more blocks. Every block consists of:
- a header of two 0xFF bytes (required for the first block, optional for subsequent blocks)
- memory address where to load the data (16-bit little endian)
- memory address of the last byte (16-bit little endian)
- the data of the block (
end_address-start_address+1
bytes)
In real Atari executables memory locations 0x2E0-0x2E1 specify the run address and 0x2E2-0x2E3 specify the initialization address. In the SAP format these are ordinary RAM locations with no special treatment.
Example:
Files that end in the middle of block data or the addresses are considered malformed, but some SAP players accept them.
Execution Model
The program from the SAP file is run inside an emulated machine that resembles a limited Atari computer with the 6502 processor, POKEY chip (at least its audio part) and 64 KB RAM. Some players include emulation of parts of the ANTIC and GTIA chips, as well as the COVOX expansion. Since SAP files may be played on a real Atari, they should be prepared for the possibility that all the original hardware is present (for example PIA controlling memory bank switching).
Memory map:
- 0000-CFFF
- RAM.
- D000-D0FF
- GTIA chip mirrored 8 times. ASAP maps just the PAL register at D014 for NTSC/PAL detection and the CONSOL register at D01F for 1-bit sounds. The rest is RAM.
- D100-D1FF
- reserved for parallel devices connected to the Atari, do not use.
- D200-D2FF
- POKEY chip mirrored 16 times or two POKEY chips (stereo) mirrored 8 times. At least the AUDF1-4, AUDC1-4, AUDCTL and RANDOM registers must be implemented in a SAP player. Emulation of timer interrupts via IRQEN and IRQST is strongly recommended. SAP by Adam Bienias emulates only timer 1 interrupts.
- D300-D3FF
- reserved for the PIA chip, do not use.
- D400-D4FF
- ANTIC chip mirrored 16 times. SAP files may rely on WSYNC (D40A) and VCOUNT (D40B) registers. ASAP also implements NMIST/NMIRES (D40F), but not NMIEN (D40E). The playback routine should be driven by the PLAYER/FASTPLAY mechanism instead of directly programming ANTIC interrupts.
- D500-D5FF
- reserved for cartridge, do not use.
- D600-D6FF
- COVOX chip if enabled via the COVOX tag (ASAP only). The COVOX consists of four unsigned 8-bit DACs: 0 and 3 for the left channel, 1 and 2 for the right channel.
- D700-D7FF
- reserved for hardware expansions, do not use.
- D800-FFFF
- RAM. FFFE/FFFF is 6502's interrupt vector for POKEY timer interrupts.
Timing: The main clock is 1773447 Hz (PAL) or 1789772.5 Hz (NTSC). There are 114 cycles per scanline, including 9 cycles memory refresh when the 6502 is stalled - same as in the Atari with ANTIC DMA disabled completely. WSYNC and VCOUNT registers may be used for delays. Note that some SAP players reset VCOUNT at the FASTPLAY rate instead of every frame.
Player Types
The value of the TYPE tag determines how the player routine gets called by the SAP player:
- TYPE B
- The player is initialized by loading the zero-based subsong number into the accumulator and calling the routine specified in the INIT tag. The routine must return with an RTS. Then, every FASTPLAY scanlines (312 being the default) the PLAYER routine is called. It must return with an RTS as well.
- TYPE C
-
This type is for convenient handling of music composed in CMC (Chaos Music Composer) . The player is initialized using the values of MUSIC, PLAYER and DEFSONG as follows:
lda #$70 ldx #<MUSIC ldy #>MUSIC jsr PLAYER+3 lda #$00 ldx #DEFSONG jsr PLAYER+3
Then, in FASTPLAY intervals, PLAYER+6 is called. When switching subsongs, the above procedure is repeated with the subsong number instead of DEFSONG.
- TYPE D
- This is similar to TYPE B, but used for digitalized music. The difference is that the INIT routine must not return. It should play the digitalized music. It can use WSYNC and VCOUNT registers and/or POKEY timer interrupts for timing. The POKEY interrupts can be programmed via IRQEN/IRQST/AUDF1-4/AUDCTL registers, the FFFE/FFFF interrupt vector and the I 6502 flag (which is initially clear, allowing interrupts). All 6502 registers (including flags) are saved when calling the PLAYER routine and restored when it returns to the running INIT routine. In ASAP 2.1.0 and above, the PLAYER tag is optional for TYPE D. Beware that in many players the first call to PLAYER usually occurs before the first instruction of INIT gets executed.
- TYPE S
- This is a convenience type for music composed in SoftSynth. The PLAYER tag is not used here, yet some SAP players require it. Instead of the PLAYER routine, at FASTPLAY intervals the memory location 0x45 is decreased and if reaches zero, the memory location 0xB07B is increased. The default FASTPLAY for this type is 78.
- TYPE R
- The data part is a raw dump of the POKEY registers (D200-D208) in FASTPLAY intervals, instead of an Atari executable. No mainstream SAP player supports this type at the time of writing.
Game_Music_Emu supports only types B and C.
When 6502 routines get called, don't assume register values except for the specified above. For example, don't assume that the INIT routine starts with zero in the X register. Also, don't assume that 6502 registers are unchanged between the calls to PLAYER or from INIT to PLAYER.
When starting a song, a SAP player must initialize POKEY registers to: AUDF1-4 = AUDC1-4 = AUDCTL = IRQEN = 0, SKCTL = 3.