THE XBIOS 'DOSOUND' FUNCTION EXPLAINED by Richard Karsmakers
Being as much a music freak as I am, I really desired to go right
through to the bottom of the ST's built-in XBIOS 'Dosound'
routine, XBIOS number 32. According to Data Becker's "ST Intern",
this function offered a really comfortable way to program sounds
on the ST. Well, I thought, let's go and have a look at the whole
thing and look what's really happening downthere when you hear
First, let's have a look at the disassembled listings of the
routines that have to do with sound on the ST.
The actual sound routine - SNDIRQ (Sound Interrupt)
FC2F84 MOVEM.L D0-D1/A0,-(A7) !Save registers for later use
FC2F88 MOVE.L $0E44(A5),D0 !Check location - Data present?
FC2F8C BEQ $FC3016 !No - leap to end of routine
FC2F90 MOVE.L D0,A0 !Put address of sound data in A0
FC2F92 MOVE.B $0E48(A5),D0 !Load timer value
FC2F96 BEQ $FC2FA0 !New sound started?
FC2F98 SUBQ.B #1,D0 !Timer-1 if new sound started
FC2F9A MOVE.B D0,$0E48(A5) !Put back timer
FC2F9E BRA $FC3016 !Ready!
FC2FA0 MOVE.B (A0)+,D0 !Get sound command from table
FC2FA2 BMI $FC2FD2 !Bit 7 set (Negative)?
!This identifies special command
FC2FA4 MOVE.B D0,$FF8800 !Register select to soundchip
FC2FAA CMPI.B #$07,D0 !Register 7?
FC2FAE BNE $FC2FCA !No
FC2FB0 MOVE.B (A0)+,D1 !Read data for register 7 in D1
FC2FB2 ANDI.B #$3F,D1 !Isolate bits 0-5
FC2FB6 MOVE.B $FF8800,D0 !Read mixer
FC2FBC ANDI.B #$C0,D0 !Isolate bits 6-7
FC2FC0 OR.B D1,D0 !'Or' data with that
FC2FC2 MOVE.B D0,$FF8802 !Byte to soundchip
FC2FC8 BRA $FC2FA0 !Get next sound command
FC2FCA MOVE.B (A0)+,$FF8802 !Data directly to soundchip
FC2FD0 BRA $FC2FA0 !Get next sound command
!This is special command routine
FC2FD2 ADDQ.B #1,D0 !Check if command was $FF
FC2FD4 BPL $FC3008 !Branch to timer-wait loop
FC2FD6 CMPI.B #$81,D0 !Was the command $80?
FC2FDA BNE $FC2FE2 !No
FC2FDC MOVE.B (A0)+,$0E49(A5) !Store temporary register
FC2FE0 BRA $FC2FA0 !Get next sound command
FC2FE2 CMPI.B #$82,D0 !Was the command $81?
FC2FE6 BNE $FC3008 !No; branch to timer-wait loop
FC2FE8 MOVE.B (A0)+,$FF8800 !Select register
FC2FEE MOVE.B (A0)+,D0 !Increment value
FC2FF0 ADD.B D0,$0E49(A5) !Add temporary value
FC2FF4 MOVE.B (A0)+,D0 !End value
FC2FF6 MOVE.B $0E49(A5),$FF8802 !Temporary value to sound chip
FC2FFE CMP.B $0E49(A5),D0 !Compary temp. value with D0
FC3002 BEQ $FC3012 !End reached? Then end!
FC3004 SUBQ.W #4,A0 !Pointer back to same command
FC3006 BRA $FC3012 !End
FC3008 MOVE.B (A0)+,$0E48(A5) !Next value as wait-timer
FC300C BNE $FC3012 !Not equal to zero?
FC300E MOVE.W #$0000,A0 !Sound vector to 0
FC3012 MOVE.L A0,$0E44(A5) !And save that
FC3016 MOVEM.L (A7)+,D0-D1/A0 !Get back registers
FC301A RTS !Return from subroutine
And here's the actual 'Dosound' routine, that is called by XBIOS
FC2ECE MOVE.L $0E44(A5),D0 !Get soundstatus
FC2ED2 MOVE.L $0004(A7),D1 !Get address of sound table
FC2ED6 BMI $FC2EE0 !Negative? Then don't set it
FC2ED8 MOVE.L D1,$0E44(A5) !Set new table
FC2EDC CLR.B $0E48(A5) !Start sound timer for the
FC2EE0 RTS !Return from subroutine
This is the routine that causes the bell to sound.
FC201C BTST #$02,$0484(A5) !Bell tone enabled?
FC2022 BEQ $FC2032 !No? Don't sound
FC2024 MOVE.L #$00FC301C,$0E44(A5) !Move bell table address
FC202C MOVE.B #$00,$0E48(A5) !Start sound timer
FC2032 RTS !Return from subroutine
And this is the routine that sounds the keyclick.
FC2A14 BTST #$00,$0484(A5) !Keyclick enabled?
FC2A1A BEQ $FC2A2A !No? Don't sound
FC2A1C MOVE.L #$00FC303A,$0E44(A5) !Move click table address
FC2A24 MOVE.B #$00,$0E48(A5) !Start sound timer
FC2A2A BCHG #$04,D1 !Invert bit 4 of D1
FC2A2E MOVE.B D1,$0E1B(A5) !Store that in $0E1B
FC2A32 RTS !Return from subroutine
The SNDIRQ routine is actually always executed, but you normally
never notice that; when no command is given (no pointer is set)
to execute a sound (this can be a key click, a bell tone or a
complete musical composition) the routine just immediately exits
and gives back control to the OS program until it is called
again, at which moment it again test whether a pointer is set.
As can be seen in the disassembled listing (made with Templemon
V1.6, by the way), that pointer has to be located on location
$0E44 (by which the contents of address register 5 are added). So
theoretically any address in memory can be used to put that
Whenever an pointer to a sound data table is put in that address,
the music starts playing. Simple, eh?
But now, let's have a look at the specific way in which that
sound data is built up. What is necessary to create a sound?
In the sound data table, the following command may be used:
$0x Load the next byte in soundchip register x,
where 'x' can vary from $0 to $F
$80 Loads the next byte into a temporary register
(This is $0E49, to which A5 is added)
$81 This command is followed by three bytes:
1st: Specifies the register ($0-$F)
2nd: Increment value (compare with STEP
value in Basic)
3rd: End criterium (when the temporary
register, to which the increment
value is added all the time, has
reached this criterium, current
execution is stopped)
$82-$FF Timer wait loop command (this is followed
a byte that signifies the number of timer
ticks that should pass before the next
command should be executed. If 0, the
whole sound is stopped; end of music)
In the first 'newlook' issue of ST NEWS (Volume 2 Issue 1), we
had included a piece of music that was programmed using the Xbios
'Dosound' command table syntax. All the musical compositions in
our Synth Sample IV were also made using this convention.
Many games use the 'Dosound' function (e.g. "Wanderer" and "Space
Pilot"), because it offers some basic sound possibilities, and it
automatically adapts the speed to the current resolution (VBL
techniques take care that a sound runs much faster in high-or
even in medium res mode than in low res mode). Really terrific
sounds, however, will probably have to be programmed using own
routines (that's what Rob Hubbard and Holger Gehrmann do,
anyway). Most programmers who don't use the 'Dosound' function,
use the VBL-queue (that's a list of longword addresses starting
on $4CE, that are executed at every vertical blank (VBL)).
An example of a music program that uses the 'Dosound' function is
"Musix32" from Tommy Software in Germany (read our review in ST
NES Volume 2 Issue 1). It enables you to save in the 'Dosound'
format, so you can easily include the musical compositions in
your own programs.
A final hint: In GfA Basic, it should be possible to keep track
of 'Dosound' music using this following short routine:
!First you'll have to execute the music
This can be easily concluded when you have a look at the actual
'Dosound' listing; on address $FC2ED6 the program checks if the
pointer is negative. If it is, then it doesn't set the sound
anew, but just continues playing it.
One last thing: The routines explained in this article are taken
from ROM TOS version 0.19. If you try some of the hints in this
article on disk TOS, you'll find out that they don't work!
The text of the articles is identical to the originals like they appeared in old ST NEWS issues. Please take into consideration that the author(s) was (were) a lot younger and less responsible back then. So bad jokes, bad English, youthful arrogance, insults, bravura, over-crediting and tastelessness should be taken with at least a grain of salt. Any contact and/or payment information, as well as deadlines/release dates of any kind should be regarded as outdated. Due to the fact that these pages are not actually contained in an Atari executable here, references to scroll texts, featured demo screens and hidden articles may also be irrelevant.