"A squirrel is just a rat with good PR."
YOUR SECOND GFA BASIC 3.XX MANUAL
- or -
HOW I LEARNED TO STOP WORRYING AND LOVE GFA-BASIC
PART 17
CHAPTER SIXTEEN - SOUND
by Han Kempen
Soundchip
If you play a note on an instrument, the volume changes in four
steps:
Attack - volume raises from 0 to peak
Decay - volume falls back to sustain-level
Sustain - constant volume during playing of the note
Release - volume falls from sustain-level to 0
This can be drawn as a so-called ADSR-envelope with the time on
the x-axis and the volume on the y-axis. A typical ADSR-envelope
looks like this:
*
* *
* * * * *
* *
* * * * *
|---|-|-----|-|------
A D S R
Of course things are never simple in the real world. We will
assume that a note has one sharply defined frequency, although
'real' notes usually are a complex mixture of different
frequencies, each with its own ADSR-envelope. That's where
samples come into the picture, but there they leave our picture
again as we will stick to sounds of one frequency.
The soundchip in your Atari ST can use eight different
'envelopes' that are rather crude compared to ADSR-envelopes.
There is no Decay or Sustain, and it even can be argued that
there are only two envelopes:
|--| = envelope-period
*
**
* *
slow Attack, fast Release: * * * * * (Attack-bit = 1)
*
**
* *
fast Attack, slow Release: * * * * * (Attack-bit = 0)
The envelope-period determines how long it takes to get back to
volume 0.
Some envelope-variations are possible by changing bit 0-3 in
register R13 of the soundchip:
bit 0 (Hold) - hold last volume (at end of first
period; overrides bit 1 and 3)
bit 1 (Alternate) - 2nd period 'mirror-image' of 1st, etc.;
Hold + Alternate = fast reverse of last
volume and hold
bit 2 (Attack) - as described earlier
bit 3 (Continue) - repeat first period indefinitely
Here are the different envelope-shapes that can be created by
combining the four bit-switches in register R13 of the soundchip:
|--|--|--|--|--| envelope-periods
*
**
* *
* * * * * * * &X00.. (bit 0 and 1 are ignored)
*
**
* *
* * * * * * * &X01.. (bit 0 and 1 are ignored)
* * * * *
** ** ** ** **
* ** ** ** ** *
* * * * * * &X1000
* * *
** * * * *
* * * * * *
* * * * &X1010
* * * * * * *
** *
* **
* * &X1011
* * * *
** ** ** **
* * * * * * * *
* * * * * &X1100
* * * * * *
*
*
* &X1101
* * *
* * * * *
* * * * *
* * * &X1110
I count 8 different envelopes, not 10. But I never was good in
counting. The envelopes &X0000 and &X0100 can be used for short
shot-like sounds (if the envelope-period is short). With the
other six envelopes you can produce continuous sound.
The soundchip has 16 byte-registers (R0 - R15), with the
following functions (range of values is also shown):
R0 - period of channel A (= channel 1 for SOUND) : 0-255 (fine)
R1 - period of channel A : 0-16 (coarse)
R2 - period of channel B (= channel 2) : 0-255 (fine)
R3 - period of channel B : 0-16 (coarse)
R4 - period of channel C (= channel 3) : 0-255 (fine)
R5 - period of channel C : 0-16 (coarse)
R6 - noise-period : 0 - 31
R7 - mixer of 8 switches (0 = on, 1 is off!):
bit 0 - channel A
bit 1 - channel B
bit 2 - channel C
bit 3 - noise on channel A
bit 4 - noise on channel B
bit 5 - noise on channel C
bit 6 - I/O register R14 (0=input, 1=output; port A)
bit 7 - I/O register R15 (port B, i.e. the Centronics port)
R8 - volume channel A (bit 4: use envelope) : 0 - 15
R9 - volume channel B (bit 4: use envelope) : 0 - 15
R10- volume channel C (bit 4: use envelope) : 0 - 15
R11- envelope-period : 0 - 255 (fine)
R12- envelope-period : 0 - 255 (coarse)
R13- envelope-shape (bit 0 - 3) : see earlier
R14- I/O (don't touch this register!)
R15- I/O (don't touch this register!)
Combining R0 and R1 you get a 12-bit value for the period
(256*R1+R0, value 1 - 4095) and the same applies to R2/R3 and
R4/R5. Converting a period to a frequency and vice versa is easy:
period = 125000/frequency and frequency = 125000/period
According to my calculator the soundchip has a frequency-range
of 31 - 125,000 Hz. Frequencies above 18,000 Hz (period < 7) are
not very useful, because most people can't hear such high notes.
One sound-period (or perhaps better: one sound-tick) equals 8.10-
6 second or 8 µs.
The two equations on the previous page are also valid for the
noise-period (R6). The noise-period is used for all channels that
are noise-enabled by the mixer (R7). The frequency of the noise
ranges from 4032 to 125,000 Hz.
The mixer (R7) uses the bits 'the other way around': a set bit
means off and a cleared bit means on. Bit 6 and 7 normally are
set (=output).
In R8/R9/R10 you set bit 4 if you want to use an envelope
(determined by R13) and in that case the volume (bit 0 - 3) is
ignored completely. Volume 0 will turn the sound on that channel
off.
Combining R11 and R12 you get a 16-bit value for the envelope-
period (256*R12+R11, value 0 - 65535). For the envelope-period
you need other equations:
period = 7812.5/frequency and frequency =
If my calculator is correct, the envelope-frequency ranges from
0.12 to 7812.5 Hz. One envelope-period (or better: one tick)
equals 128 µs. At the maximum period of 65535 the envelope &X1000
will reach the volume-peak every 8.4 seconds (0.12 Hz). The
envelope-period has nothing to do with the sound-period. The
former determines the frequency of the volume-changes (see the
envelope-shapes mentioned above). The latter determines the
frequency (pitch) of a sound.
The chosen envelope-shape (R13) will be used by all three
channels.
Keep your hands off R14 and R15. The soundchip is used for some
I/O-work and you should not interfere with that. That's probably
the reason that with some sound-software the drive-light is on
although drive A is not used.
There are a few Public Domain soundchip-editors around that
should make it easy to construct interesting sounds. Although
it's nicer to write your own editor. With all the information
about the soundchip in this paragraph you should be able to do
that. But you'll have to read the paragraph 'Dosound (XBIOS 32)'
as well, because there you will find out how to change the
registers and, not unimportantly, how to play the sound.
SOUND and WAVE
A short explanation about the connection between the (two
versions of the) SOUND-command and the soundchip-registers from
the previous paragraph:
SOUND channel,volume,note,octave,time
SOUND channel,volume,#period,time
Note and octave are converted to period, so the two versions are
equivalent. The variables have the following meaning:
channel (1,2,3) = channel A,B or C in bit 0-2 of R7
volume (0-15) = volume in R8, R9 or R10
note/octave = (converted to) sound-period
period (1-4095) = sound-period in R0/R1, R2/R3 or R4/R5
time ('PAUSE') = used by XBIOS 32: CHR$(130)+CHR$(time)
The WAVE-command is more complicated:
WAVE mixer,envelope,shape,period,time
mixer (switches + 256*noise-period) = R7 + 256*R6
envelope (use envelope: &Xcba) = bit 4 of R8, R9 & R10
shape (envelope-shape) = R13
period (envelope-period) = R11/R12
time = see SOUND
The time-parameter in the SOUND- and WAVE-command determines
when the next Basic-command will be executed, just like a PAUSE-
command does. If you hear a continuous sound (e.g. with envelope
&X1000) you have to use another SOUND- or WAVE-command to stop
the sound.
The easiest way to stop all sound is:
WAVE 0,0 ! turn all sound off
There are several ways to represent notes and that might confuse
you a bit. Assuming you have a rudimentary knowledge of music,
the twelve notes in one octave can be represented by letters:
C C# D D# E F F# G G# A A# B
1 2 3 4 5 6 7 8 9 10 11 12 (SOUND-notes)
For SOUND you use the corresponding numbers 1 - 12. Often the
octave-number is inserted behind the note-letter:
C1 C1# D1 D1# E1 F1 F1# G1 G1# A1 A1# B1
1 2 3 4 5 6 7 8 9 10 11 12
(SOUND-octave = 1)
This is the first octave on my synthesizer. C3 is often referred
to as the 'middle C' and that note has a frequency of 262 Hz. If
you take C4, you are one octave higher, and this means that the
frequency has doubled (524 Hz). The highest note on my
synthesizer is C6. With SOUND you can play even higher notes,
e.g. C9 (note 1, octave 9; at 16,744 Hz it almost hurts my ears).
If SOUND-note and -octave are known, the frequency and SOUND-
period of the note can be calculated:
frequency%=55*2^(octave+(note-10)/12)
period%=125000/frequency%
To make things a little more complicated, my synthesizer knows
nothing about notes, octaves or periods. It only recognizes MIDI-
notes, which are bytes with a value of 0 to 127 (bit 7 is not
used). E.g. C3 is MIDI-note 60. Wouldn't it be nice to know how
to convert MIDI-notes to SOUND-note and -octave? I think this
should work:
octave=INT(MIDI.note|/12)-2
note=MOD(MIDI.note|,12)+1
Using the other two equations you can now convert MIDI-notes to
frequency (in Hz) and SOUND-period as well. Here is our octave
again, so you can check the results:
C1 C1# D1 D1# E1 F1 F1# G1 G1# A1 A1# B1 first octave
1 2 3 4 5 6 7 8 9 10 11 12 SOUND-notes
36 37 38 39 40 41 42 43 44 45 46 47 MIDI-notes
In chapter 12 you can read a little bit more about MIDI.
You don't have a synthesizer, but would like to play some simple
MIDI-music? Or you would like to convert an XBIOS 32 song to a
MIDI-song for your synthesizer? Then you should know the
following MIDI-commands (consisting of two or three consecutive
bytes):
first second third MIDI-
byte byte byte command
&H8n note velocity note off (channel n)
&H9n note velocity note off (channel n)
&HBn &H7B &H0 all notes off (channel n)
&HCn number - program change (chan.l n)
Other MIDI-commands should probably be ignored completely if you
don't have a synthesizer. The low nibble of the first byte (bit
0-3) determines the channel. E.g. &H80 means channel 0 and &H8F
means channel 15. Most MIDI-programs present channel 1 - 16 to
the user, but internally channel 0 - 15 (&H0 - &HF) is used. The
high nibble of the first byte determines the command. A note can
have a value of 0 - 127 (bit 7 is always 0), as mentioned before.
Of course you'll have to convert a MIDI-note to the proper SOUND-
note/octave. The velocity also has a value of 0 - 127. For SOUND
that has to be converted to a volume-range of 0 - 15 (the SOUND-
range is not linear, to make it more complicated). If a note is
on, you have to send a 'note off' command later, although you can
also use the 'note on' command with velocity 0. A program change
can be used to switch to another instrument. You'll need some
sort of timer to measure the time between the MIDI-commands.
That's all. Good luck.
Dosound (XBIOS 32)
XBIOS 32 (Dosound) can be used to play music in a special
format. 'X32' is now generally recognized as the standard-
extension for song-files in this format. The operating system
takes care of playing the music during Timer C interrupts (every
1/50th second):
' Piece of music of 2140 bytes in INLINE-line
INLINE music%,2140
~XBIOS(32,L:music%) ! play the music
You can even play a song continuously with the aid of EVERY.
Temporarily stopping a song is also possible, because you can
determine where you are:
pointer%=XBIOS(32,L:-1) ! song-position (0 = end!)
WAVE 0,0 ! silence
You'll have to save the soundchip-registers with XBIOS 28
(Giacces) or you won't be able to continue the song later:
DIM register(15)
' Save registers
FOR i=0 TO 15
register(i)=XBIOS(28,0,i)
NEXT i
(...)
' Restore registers
FOR i=0 TO 15
~XBIOS(28,register(i),i OR 128)
NEXT i
~XBIOS(32,L:pointer%) ! continue where we left
If you use XBIOS 32 to play music, you are advised to switch the
key-click off. Otherwise the music will stop as soon as the user
presses a key. If you return to the GFA-editor, the key-click is
sometimes garbled. Enter some illegal command and GFA will
restore the proper key-click and inform you about your stupid
error.
XBIOS 32 can also be used for sound-effects. I have developed a
standard
method for building sound-strings from a few DATA-lines. In the following
example the sound-string s$ is created:
' commands in DATA-lines :
' REG = 14 parameters for soundchip-registers R0-R13
' END = end of sound-string
' PAUSE = pause (followed by time in 1/50 seconds)
' VAR = decrease/increase tone: channel,start,+/-step,end
' start and end: 0-255
bounce3.sound:
DATA REG,0,0,0,0,0,0,27,248,16,16,16,35,95,0
DATA VAR,3,255,-1,116
DATA PAUSE,255,END
RESTORE bounce3.sound
'
s$=""
DO
READ snd$
snd$=UPPER$(snd$)
EXIT IF snd$="END"
IF snd$="REG"
FOR n=0 TO 13
READ snd
s$=s$+CHR$(n)+CHR$(snd)
NEXT n
ENDIF
IF snd$="PAUSE"
READ snd
s$=s$+CHR$(130)+CHR$(snd)
ENDIF
IF snd$="VAR"
READ channel,begin,step,end
s$=s$+CHR$(128)+CHR$(begin)+CHR$(129)+CHR$(channel)+
CHR$(step)
s$=s$+CHR$(end)
ENDIF
LOOP
s$=s$+CHR$(255)+CHR$(0) ! add terminator
'
~XBIOS(32,L:V:s$) ! let's hear the sound
In the paragraph 'Soundchip' you already read everything there
is to know about the registers. The VAR-command makes it possible
to create sounds with decreasing/increasing pitch. You don't have
to use the sound-strings as such, you can save a string as a file
or you can store the data in an INLINE-line.
Samples
From GFA-Basic you can surprise the user with a sampled sound if
you have a routine that plays the sample. BASCODE.EXE (from
Replay) is widespread. You'll have to find suitable samples
first. Look out for sound-effects and speech-samples. Personally,
I just love the famous Perfect-sample. There are also complete
sampled music-pieces around, but such files are always multi-K.
Speech
Your ST can talk to you with a little help (STSPEECH.TOS), but
my current GFA-version (3.07) refuses to cooperate with
STSPEECH.TOS. Who can help?
Soundmachine
In the Soundmachine editor you create a so-called object-file of
a song. This file contains both the song and a routine to play
the song. The good quality of the music-sound is achieved because
the notes are sampled sounds. Soundmachine uses three independent
channels in a song. You can also incorporate sound-effects in a
song. If you're looking for the highest sound-quality you run a
song in X100-mode from a GFA-Basic program. In this mode the
processor in your ST is totally dedicated to playing the song, so
your GFA-program comes to a complete standstill. For a good
compromise between sound-quality and speed you run a song in X66-
mode. Now your program keeps running, although much slower, and
the sound-quality still is good. You can also use the Mini
Soundmachine editor to make beautiful music together. Because
Mini Soundmachine makes optimal use of the soundchip, your GFA-
program runs almost as fast as normal but the sound-quality is
much less than with Soundmachine. You can improve the sound-
quality by using a sample on one channel, but that will slow your
program down. Try it and decide yourself which song-type fits
your program best.
I saved the best news for now: Soundmachine is available as
Shareware. As this is the only music-program that I can recommend
for GFA-Basic, my advice is: find it, use it and pay your share.
If you already have Soundmachine, please follow these
guidelines:
Always enclose the original Soundmachine song (*.SNG) or
Mini Soundmachine song (*.MSG) if you spread your GFA-
program with music. Other owners of Soundmachine will
appreciate it!
An Object-file (*.OBJ) is suitable for your GFA-program
only. Give information about the song in your program,
especially about the use of Flags.
Use the extension MSM for an object-file of a Mini
Soundmachine song that can be used with any program. The
object-file should contain one song in an endless loop.
Use the extension X10 for an Object-file of a (compressed)
Soundmachine song that plays in X100-mode only.
Use the extension XSM for an Object-file of a (compressed)
Soundmachine song that can be played either in X66- or X100-
mode. Such a song should contain:
X66 L-P-[all 3 channels] :0 F0,0 :1 XX R1,0,0 R2,0,100
R3,0,66 J0 :2 X100 :3 [actual song] J3
In your GFA-program you should set Flag 0 to 100 for X100-
mode, or to 66 for X66-mode. Use Flag 0 for this purpose
only.
GIST
GIST (GI Sound Tool by Lee Actor, (c) Synthetic Software) is a
program that allows you to create 'true' ADSR-envelopes. In GFA-
Basic you can use a GIST-sound quite easily. Sounds can be used
as sound-effects, but you can also play notes. Sound-effects can
be pretty impressive compared to XBIOS 32 sounds. GIST has no
music-editor (I hope you write one for me), so you have to do
some extra work. If you have a piece of music in MIDI-note
notation it's easy, because the GIST-driver uses MIDI-notes (24-
108, see paragraph 'SOUND and WAVE').
TCB Tracker
With the TCB Tracker editor (by Anders Nilsson, not Public
Domain) you can create music on four tracks (= channels). As in
Soundmachine the notes are sampled sounds, so the quality is
pretty good. You can play TCB Tracker songs (*.MOD) in GFA-Basic,
but only if you use a colour monitor with a vertical frequency of
50 Hz. At 60 Hz the music may still sound acceptable, but at 72
Hz (High resolution) it's played too fast. Your GFA-program is
halted completely and you can only stop a song by pressing
<Space>. Unless the replay routine is improved drastically, I
can't really recommend TCB Tracker for GFA-Basic programs.
Staccato
I was not impressed by the program Staccato (by Leo de Wit), but
I really liked the music (*.MUS) that can be played with that
program. A lot of effort was put into the large collection of
music-files. What a waste. Unless somebody has a replay routine
for Staccato. Or, better still, a program to convert the *.MUS-
files (ASCII-format) to XBIOS 32 format.
Music Studio
Only one question about Music Studio: does anybody have a replay
routine for playing Music Studio song-files (*.SNG) in a GFA-
Basic program? Please?
Procedures (CHAPTER.16)
Bell BELL
The wellknown bell-sound:
@bell(5) ! ring the bell 5 times
No Nobel prize for this Procedure.
Cont_song_play and Cont_song \CONTSONG\CONTPLAY
Play a song in XBIOS 32 format (*.X32) continuously with EVERY:
INLINE music%,1458
@cont_song_play(music%)
The key-click is switched off by this Procedure. The music will
play continuously, until you either call the Procedure
Cont_song_break or Cont_song_stop.
Cont_song_stop \CONTSONG\CONTSTOP
Stop the song that was started with Procedure Cont_song_play:
INLINE music%,1458
@cont_song_play(music%)
(...)
@cont_song_stop
The key-click is switched on again.
Cont_song_break and Cont_song_continue \CONTSONG\CONT_BRK
Interrupt a continuously playing song:
INLINE music%,1458
@cont_song_play(music%)
(...)
@cont_song_break ! key-click switched on
(...)
@cont_song_continue ! continue where we left it
(...)
@cont_song_stop
Dosound_init and Dosound_string DOSND_IN
Create sound-strings for Procedure Dosound:
@dosound_init
The sounds are created as global string-variables.
Dosound DOSOUND
Play an XBIOS 32 song or a sound-string from Procedure
Dosound_init
INLINE music%,1458
@dosound(music%)
(...)
WAVE 0,0 ! silence
@dosound(V:soundeffect$)
Gist_init/exit/on/off/stop/prior/stop_all \GIST\*
Play GIST-sound (sound-effect or piece of music):
INLINE gist.driver%,3000
INLINE gist.effect%,112
INLINE gist.note%,112
@gist_init
(...)
' sound-fx on channel 1, default volume/note, priority 10
@gist_on(gist.effect%,1,-1,-1,10)
' you don't need Gist_off for a sound-effect
(...)
' note on channel 2, volume 10, MIDI-note 48, priority 1
@gist_on(gist.note%,2,10,48,1)
PAUSE 3*50
@gist_off(2) ! note off after 3 seconds
(...)
@gist_exit ! absolutely essential
Msm_init/start/stop/effect/flag/exit \MINI_SM\*
Load Mini Soundmachine object-file and play the music:
@msm_init("A:\SONG.MSM",ok!) ! load the music
IF ok!
@msm_start ! play the music
ELSE
' something went wrong
ENDIF
(...)
@msm_stop ! stop the music
(...)
@msm_exit ! absolutely essential
Sample SAMPLE
Play a suitable sample:
INLINE sample.bascode%,2794
INLINE sample.adr%,20000
@sample(sample.adr%,20000,5) ! speed=5
PAUSE 10
Sm_init/flag/start_x100/wait/start_x66/stop_x66/space/exit
Load Soundmachine object-file and play the music: \SND_MACH\*
@sm_init("A:\SONG.XSM",70000,ok!) ! load the music (70000=
buffer)
IF ok!
@sm_flag(0,66) ! X66-mode
@sm_start_x66 ! play the music
ELSE
' something went wrong
ENDIF
(...)
@sm_stop_x66 ! stop the music
(...)
@sm_exit ! absolutely essential
Song_play and Song_stop \SONG\ SONGPLAY & SONGSTOP
Play XBIOS 32 song (*.X32) once:
INLINE music%,2057
@song_play(music%) ! song keeps playing until finished
(...)
@song_stop ! stop song prematurely
Song_restart \SONG\SONGREST
Restart song that was stopped with @song_stop:
@song_stop
(...)
@song_restart
Song_break and Song_continue \SONG\SONG_BRK
Interrupt a song that was started with @song_play:
INLINE music%,2057
@song_play(music%)
(...)
@song_break ! key-click switched on
(...)
@song_continue ! continue where we left the song
The music now keeps playing until the end, or until Procedure
Song_stop is called.
The following Procedures use SOUND and/or WAVE to produce a
sound: \SOUND\
Sound_alarm ALARM
Sound_boing_1 BOING_1
Sound_boing_2 BOING_2
Sound_cling CLING
Sound_heart HEART
Sound_pompom POMPOM
Sound_poof POOF
Sound_siren_1 SIREN_1
Sound_tideli TIDELI
Sound_ting TING
Sound_tong TONG
Tcb_tracker TCBTRACK
Play a TCB Tracker song (*.MOD):
@tcb_tracker("A:\SONG.MOD",TRUE)
The replay-routine TRACKER.ROT (for ST's, not STE's) must be in
the default-path. You have to press <Space> to stop the music.
Functions (CHAPTER.16)
Frequency FREQ
Returns frequency (Hz) of note/octave:
PRINT @frequency(1,3) ! C3
Frequency_MIDI FREQMIDI
Returns the frequency (Hz) of a MIDI-note:
PRINT @frequency_MIDI(60) ! that's C3 also
MIDI_byte MIDIBYTE
Returns the MIDI-note that corresponds with note/octave:
PRINT @MIDI_byte(1,3)
Octave OCTAVE
Returns the SOUND-octave of a MIDI-note:
PRINT @octave(60)
Note NOTE
Returns the SOUND-note of a MIDI-note:
PRINT @note(60)
Period PERIOD
Returns the SOUND-period of note/octave:
PRINT @period(1,3)
Period_MIDI PERDMIDI
Returns the SOUND-period of a MIDI-note:
PRINT @period_MIDI(60)
Disclaimer
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.