home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Large Pack of OldSkool DOS MOD Trackers
/
trjoy094.zip
/
TECH.DOC
< prev
next >
Wrap
Text File
|
1995-01-09
|
32KB
|
801 lines
┌───────────────────────────────────────────────────────────────────────────┐
│ TRACKJOY - Gravis Ultrasound Tracker by RSC │
│ (c) Copyright 1993, 1994, 1995 Tomi Joy │
│ All rights reserved │
│ Programming & documentation: Tomi Joy │
│ │
│ TECHNICAL DOCUMENTATION for programmers │
│ │
│ *** NOTE: This is not supposed to be a particularly pretty │
│ document, but is does supply some useful and │
│ possibly interesting information. │
│ │
│ Specs are theoretically for Trackjoy version 1.00, │
│ which is technically equivalent to all the │
│ less than or equal to 1.00 beta versions. │
│ The file format specifications currently cover │
│ *file* versions 1.0 and 1.1, the only difference being │
│ in the way four bytes in then sample controllers are used. │
│ │
└───────────────────────────────────────────────────────────────────────────┘
■ Note: You might see some references to a program called Instrument
Maker in this document. IM is the sample editor which will be
included in future versions of Trackjoy. At the moment it doesn't
support 16-bit samples and has some severe bugs, so I didn't want to
release it yet.
■ I don't promise that the information in this document is correct
and/or up-to-date.
─────────────────────────────────────────────────────────────────────────────
Table of contents
─────────────────────────────────────────────────────────────────────────────
1. Overview
2. The Gravis Ultrasoud
3. Trackjoy system requirements + other information
4. Trackjoy music storage & playing definitions
5. File formats (.TJS, .JOY, .BLK, samples)
6. Compression schemes
7. The interrupt interface
8. The sound effect interface
─────────────────────────────────────────────────────────────────────────────
1. Overview
─────────────────────────────────────────────────────────────────────────────
The heart of Trackjoy is the playing engine. It's a relatively simple
group of functions, one of which is hooked to the timer interrupt vector
08h. This function increments counters and checks for the next notes to
play. It also checks when to damp voices down with the Ultrasound's
volume ramping register. This is done to avoid clicking when samples
are abruptly cut off. The damping timing can be adjusted to some extent.
The other functions associated with the playing engine simply fetch
the note, volume and instrument (and special command) data from the
storage array. One of the functions does the opposite of damping the
voices, ie. it lights them if the time is ripe.
Normally when an 80x86 is booted up, the timer interrupt vector points
to a routine which increments the time and date counters in the PC's
memory. The frequency at which this is done is approximately 18.2 Hz.
Unfortunately this gives rise to a problem: Trackjoy needs a 100 Hz
timer for the player engine, so the timer has to be re-programmed.
Obviously if we still keep on chaining back to the old service
routine after the player has done with an interrupt, time is going to
go too fast. If, on the other hand, we don't chain to the previous
vector at all, time is going to *stop*. Now we don't want that either.
The solution (although not a very pleasing one) is to call the old
routine only every now and then.
Trackjoy uses a 500 Hz hardware timer, but uses only every fifth tick
(100 Hz) to do anything to the music score.
Data bytes recognized by Trackjoy are the note, volume, instrument
bytes. On so-called FULL channels 3 more bytes are used: the command
and its two parameters. Notes are very straight forward: the value 0 is
C-0, 1 is C#0 and so on. When *any* of the data bytes has the falue 255
or FFh, it's an *empty* byte and is represented by dots on the Trackjoy
editing screen.
Semitones are supposed to be about 2^(1/12) * the previos note. ("The
twelth root of two" equals "two to the power of one twelth".) In
decimal this is about 1.05946. In other words, the frequency of any
note in an octave is basic_frequency * 1.05947 ^ (number_of_note). To
raise a note to an octave multiply it by 2 ^ (number_of_octave).
Actually, that is *not* exacty what Trackjoy does. It looks up notes
from a table, since it's much quicker *and* it avoids using floating
point math that way.
────────────────────────────────────────────────────────────────────────────
2. The Gravis Ultrasound
────────────────────────────────────────────────────────────────────────────
Let's be blunt: the Gravis Ultrasound card is a bugger to program.
Consider these "features" of the card from the programmer's point
of view.
1. 16-bit samples can't be played across 256k boundaries
(Memory is segmented as 1 to 4 256k banks)
2. With 32 voices in use, the maximum output frequency is only
19293 Hz, and 44.1 kHz is achieved only with 14 voices.
3. The frequency the card produces with a certain frequency
controller register value (and the speed at which volume ramping
is done) depends on the number of active voices in use.
4. Without significant programming effort, clicking is a real
problem. The click is caused by suddenly changing the DAC value by
a large degree. To remove it, you have to do a lot of careful
volume ramping register programming.
5. It only has 16 stereo pan positions. This isn't enough, because
the say in the official GUS documentation that it causes clicking.
6. Certain registers (the self-modifying ones) have to be updated
twice before you can be sure the card got the message.
─────────────────────────────────────────────────────────────────────────────
3. Trackjoy system requirements + other information
─────────────────────────────────────────────────────────────────────────────
Trackjoy was programmed in C and assembler
System requirements:
- 80286+
- EGA, although VGA is supported
- Ultrasound card (256k will do)
- about 300k free low memory
- hard disk stronly recommeneded
────────────────────────────────────────────────────────────────────────────
4. Trackjoy music storage & playing definitions
────────────────────────────────────────────────────────────────────────────
4.1 Music score is divided into patterns.
4.2 Pattern length (1-255 rows) and structure (ie. width and type
for each channel) can vary
4.3 Patterns consist of channels (max. 17 channels) Actual voice
channels are limited to sixteen in order to retain acceptable sound
quality with the GUS. In practice this will be quite enough for
almost any purpose. The 17th channel is an optional global channel
that controls all channels.
4.4 Three channel types are supported. They are:
Stripped: Only note, instrument & volume information
Full: Note, instrument, volume & special effect info
Global: Global volume & special effect information (max one per pattern)
(The CHORD type was omitted due to programming difficulties, not
actually needing it and most important of all ─ laziness.)
4.5 Notes: C-0 to B-9 (could in theory go to D-21, but that wouldn't be
practical)
4.6 Instruments: Normal 8- and 16-bit samples will be supported in version
1.0. Version 1.1 might add ADSR support to these samples. Sorry, no
GF1 patch support.
4.7 Channel sample volume: 0 - 254. This will be from a table, since
the US's volume 0-4095 is logarithmic instead of linearic.
4.8 Special effects (Full channels)
(Look for these in the next version)
4.10 Data requirements (in bytes per row per channel):
Stripped channels.... 3 bytes
Full channels........ 6 bytes
Global channels...... 4 bytes
If simple silence packing is implemented, this will be a lot less
in most instances. It probably won't, though, so no need to get
excited.
──────────────────────────────────────────────────────────────────────────────
5. File format (Trackjoy saves and loads both songs and modules)
──────────────────────────────────────────────────────────────────────────────
Trackjoy music file format version 2.0 (It *should* be impossible
to come across a version 1.X file, since this ─ the very first ─
release of Trackjoy writes file version 2.0)
Format of song (.TJS) and module (.JOY)
────────────────────────────────────────────────────────────────────
OFFSET: PURPOSE:
─────── ──────────────────────────────────────────────────────
0-7 8 bytes: "TRACKJOY"
8 1 byte: 0=song, 1=module
9 1 byte: file version, 20 decimal (20 means 2.0)
10 2 bytes (reserved, but Trackjoy writes 0x99 and 0x52)
12 1 word: default tempo
14 1 word: tempo modifier (not used)
16 1 word: master volume (max. 256)
18 1 word: volume modifier (not used)
20 1 byte: transpose
21 1 byte (reserved)
22 1 word: number of directory entries
Trackjoy can't write more than 196 (128 patterns,
64 samples + 4), and even this is more than anybody is
usually going to use.
24 Directory
[1 DWORD:PTR][1 BYTE:TAG][1 BYTE:UNUSED]
<number of dir entries> of these
The DWORD is a real byte-precision pointer to the object.
Objects will start at even byte offsets.
The first byte (tag) in a directory entry defines the
object pointed to.
Tags
0 ─ Writer information (text)
1 ─ Song name
2 ─ Song composer
3 ─ Song comment
4 ─ Pan positions
5 ─ Song order list
6 ─ Pattern
7 ─ Sample parameter block (no sample data)
8 ─ Sample parameter block + sample data
All objects in the directory are sorted in ascending
order by tag, ie., if song name exists, it will always
be before song composer etc.
The patterns come in the order in which they will be
in memory. The order of sample depends on the sample
slot (sample number) they go into, but Trackjoy writes
them in ascending order (by sample number).
Trackjoy will always write the order first, then all the
actual patterns and finally sample parameter blocks (with
or without samples). Files written by Trackjoy can be read
according to the directory almost sequentially to minimise
the necessity for random access. However, it is legal for
any of the objects to reside anywhere in the file.
Please remember that all objects start at even byte
addresses, so there will be some padding bytes around
in the file.
Note that each song and module has at least one pattern
and the order array. There may not be any instruments, and
the song information text strings are optional.
The only difference between a song and a module is
the byte at offset 8 from the file's beginning and
that in modules, the samples have tag 8 instead of 7.
Of course, the *format* allows both types of sample in
either song or module, but Trackjoy doesn't support this
at least at the moment.
Anything with a tag greater than 8 will promptly be
ignored by Trackjoy.
From here on, offsets will be relative to the beginning of the object in
question.
Format of writer information, song name, song composer and song comment:
0 1 word: length of string
2 data
Trackjoy will ignore parts of strings exceeding 80 bytes.
Trackjoy currently does not write "writer information"
at all.
Format of pan positions
0 1 word: length of string, Trackjoy currently writes 18
2 Byte array. The value 0 means left, 100 means right.
Format of sample parameter block
0 1 byte: sample number (the instrument number in patterns)
1 name: 30 (ASCIIZ)
filename: 13 (ASCIIZ)
type: 1 (0,1,2)
playmode: 1
allocated-flag: 1 (used internally by Trackjoy)
loop_beg: 4 (dw)
loop_end: 4 (dw)
length: 4 (dw)
gus_off: 4 (dw) (used internally by Trackjoy)
freq: 2 (default 4000)
sampvolume: 2 (max. 256)
padding: 2 *** Not currently used ***
Some sample (slot) numbers may not appear at all, so just
leave the left-over slots empty.
The format of a "sample parameter block + sample data" is exactly
the same as "sample parameter block" except that is is followed
by exactly <length> bytes of sample data, whether 8- or 16-bit.
<Length> is found within the parameter block.
Format of pattern:
0 1 word: rows (Trackjoy's maximum is 256, and
the absolute maximum is 512)
2 1 byte: width in channels (for first pattern)
3 1 byte (reserved)
4 1 byte: compression scheme (0=None, 1=Silence)
5 33 bytes = format array (SEE NOTE BELOW)
38 1 word = actual length of written pattern data
(length of uncompressed final pattern is computed
from the format array, the width and the number
of rows)
40 value at [38] bytes of pattern data, compressed
or uncompressed
Format of order array:
0 1 word: length (always 128)
2 128 bytes: pattern play order array, FFh = empty
*** NOTE: Each byte of the format array indicates what type of channel is at
that index. The value 0 is for FULL channels, 1 for STRIPPED
and 2 for GLOBAL channels. There are 33 bytes because TRACKJOY
is built so that it can (by modifying a #define directive) be
made to operate on max. 33 channels.
Pattern compression:
Three byte values are reserved for special purposes. They are,
in decimal, 233, 231 and 237. These values were chosen because
they are bigger than valid note, instrument or special command
values and are fairly unlikely to be entered as volumes by the
user.
Byte/byte pair Interpretation
231 Repeat FFh twice
233 Repeat FFh three times
237,0 231
237,1 233
237,2 237
237,n when n>2 Repeat FFh n+1 times
In other words, 231 and 233 are always alone. 237 is always
followed by another byte. The actual values 231 and 233 are
encoded through 237. This ensures that the worst compression
ratio when compressing strips of FFh longer than 1 byte will
be 1:2. The best is 1:128. FFh is by far the most common
byte in Trackjoy patterns. It is not worth bothering about
other values, as the extra_compression / annoyance_of_
extra_programming factor is very low indeed, not to mention
that happiness_of_Tomi = 1 / Time_spent_in_extra_programming.
Note that pattern data is compressed COLUMN BY COLUMN,
not row by row. This yields significantly better compression ratios
than row-by-row compression, since the way data is entered into
a pattern is more uniform vertically than horizontally.
Example pattern:
Let X be the width (in 1-byte parameter columns like <note>,
<ins> or <special command>) of the current pattern, and
let there be 3 rows in our pattern.
┌─┬─┬─┬─┬─┬─┬─┬─┬─── ─ ─
0+ │0│1│2│3│4│5│6│7│...
├─┼─┼─┼─┼─┼─┼─┼─┼─── ─ ─
X+ │A│B│C│D│E│F│G│H│...
├─┼─┼─┼─┼─┼─┼─┼─┼─── ─ ─
2X+ │L│M│N│O│P│Q│R│S│...
└─┴─┴─┴─┴─┴─┴─┴─┴─── ─ ─
In this pattern, you would compress or uncompress in order
0,A,L,1,B,M,2,C,N,3... What type of field you are compressing doesn't
matter, but knowing the pattern width is important. Note that
compression from column to column (for instance, from P to 5) is
allowed. This compression scheme will of course only allow compression
of strips max. 256 times FFh in length, at a time.
Uncompression example:
The string
<16><12><255><12><255><12><233><13><237><3><237><1>
uncompresses to
<16><12><255><12><255><12><255><255><255><13>
<255><255><255><255><233>.
For obvious reasons, things like
<231><231>
<231><233>
<231><237><64>
<233><255>
should never appear in the middle of a column. However, they are
perfectly correct and readable, and may occur at the very last column
of a pattern. Within a column, there are of course more logical ways of
compressing these oddities. However, <237><255> followed by <255>,
<231>, <233> or another <237><n> may appear anywhere if 257, 258 or more
FFh's are compressed.
For technical reasons, Trackjoy actually rotates and flips a pattern's
data before compression, ie. a pattern is treated as a rectangular
byte block with a width of <columns> and height of <rows>.
Ie.,
abcd aei
efgh becomes bfj which is like a 90° degree rotate clockwise
ijkl cgk and a flip horizontal.
dhl
After the 90 degree rotate (and flip) a normal run-length crunching
algorithm is used, and the output is saved to disk with the correct
parameters. This is the easiest way to do it :)
5.2 Trackjoy block file format
Format of block file (.BLK)
────────────────────────────────────────────────────────────────────
OFFSET: PURPOSE:
─────── ──────────────────────────────────────────────────────
0 11 bytes: "ÖRÖRÖRÖRÖR!"
To understand why these first eleven bytes are
"ÖRÖRÖRÖRÖR!", you really have to be an insider. Sorry
about that. (According to some not-very-reliable sources,
"ÖRÖRÖRÖRÖR!", derived from the verb "öristä", is the
closest ASCII equivalent of the the sound emitted from a
Class A Finnish "puliukko" on discovering that he has ─ in
one way or an other ─ lost contact with his best friend ─
the bottle of "Kossu". The puliukko is a species of
red-nosed scraggy-looking being completely pickled in
alcohol and found in abundance in the parks of Helsinki.
Örörörörörörör!)
11 word: left
13 word: top
15 word: right
17 word: bottom
19 word: length
21 block data in linear uncompressed full channel format
(ie., channel 1 row 0 is right after channel 0 row 0)
channel 0 row 0) END
5.3 Sample formats
5.3.1 Raw 8-bit PC8
This is the unsigned typical PC sample type with no header.
Each sample is simply a value from 0 to 255, and +128 represents
an output voltage of zero. It needs to be converted to signed
format for most purposes including volume scaling and playing
with the Ultrasound.
5.3.2 Signed raw 8-bit A8
This is the same as PC8 except that it is in signed two's
complement format. The values are signed integers from
-128 to +127, zero naturally represents an output volume
of zero.
5.3.3 Unsigned raw 16-bit S16
This is the 16-bit format Trackjoy currently reads. Samples are unsigned
16-bit integers (words) with 32768 representing the output voltage of
zero. Also this format is converted to signed 16-bit (by flipping bit
15) before loading into the Ultrasound's memory. The byte order is
low-high, ie. the least significant 8 bits of the value occupy the lower
address. This is the Intel back-words integer storage format.
5.3.4 Trackjoy headered sample format
Format of TJINSX headered sample, version 1.1
────────────────────────────────────────────────────────────────────
OFFSET: PURPOSE:
─────── ──────────────────────────────────────────────────────
0 5 bytes: "TJINS"
5 1 byte: version number, 0Bh (11 decimal = 1.1)
*** Ignore any files with this byte less than 0Bh.
6 16 bytes: "XXXXXXXXXXXXXXXX", reserved for future
use, of course
22 sample information, precisely same format
as in songs and modules (See song & module formats,
offset x+1 or definition of "sampleinfo" structure)
90 sample data in signed format, low-high byte order
for 16-bit samples, can be dumped directly into
the Ultrasound and then played
END
5.3.5 Scream Tracker III / Digiplayer sample format
Trackjoy will read the basic Scream Tracker III sample format (8-bit
mono), and Instrument maker will, in addition to reading these files,
also write them. For a definition of the Scream Tracker III / Digiplayer
sample format, consult the TECH.DOC file included in the public release
package of Scream Tracker III.
─────────────────────────────────────────────────────────────────────────────
7. The interrupt interface
─────────────────────────────────────────────────────────────────────────────
Trackjoy supports an interrupt interface for other programs to control
music (or sound effect) output. The interface can also be used for
synchronising other programs with the player engine. TRACKJOY can
hook itself to one of the interrupts between 60H ─ 66H, namely int 61h.
When the interface (int 61h) is called, AL contains the function
number. AL doesn't return a value. (W) means AH and BX contain
information to pass to TRACKJOY (functions 0h - Fh). (R) means another
program reads information from TRACKJOY, which returns it in the other
registers (AH, BX, CX and in a few cases, DX). Pointers and long ints
are dwords and are returned in the register pair BX:CX.
The interrupt can be called either from an assembly language program by
simply setting the registers to the desired values or through one of
the interrupt interfaces supplied with your high-level compiler.
(Syntax for popular C-compilers for MS-DOS offer the following
interface:
#include <dos.h>
...
call_trackjoy(void)
{
union REGS inregs, outregs;
unsigned interrupt_number = 0x61;
inregs.h.al = 0x10; /* call "READ MUSIC CONTROL" */
int86(interrupt_number, &inregs, &outregs);
/* Data returned is in outregs.h.ah, outregs.h.bl,
outregs.h.cl and outregs.h.ch, in this case. */
...
}
...)
These are the functions that are supported:
==============================================================================
WRITE COMMANDS 00h - 09h, 20h - 2Fh
==============================================================================
AL==00h (W) MUSIC CONTROL
AH = Select function: 0 = none, 1 = play/stop, 2=pause/play
1: play/stop - If BL == 0 TRACKJOY will stop
2: play/pause - If BL == 0 TRACKJOY will deep-freeze.
Ie., the timer interrupt is un-hooked from TRACKJOY,
the timer is set to 18.2 Hz and all the GUS accumulators
are frozen. This is equivalent to a pause state.
BL == 1 melts TRACKJOY...
------------------------------------------------------------------------------
AL==01h (W) MASTER VOLUME
AH = new master volume (0-255)
------------------------------------------------------------------------------
AL==02h (W) CHANNEL CONTROL
AH = number of channel
if CL == 1 TRACKJOY will mute channel <AH>
------------------------------------------------------------------------------
AL==03h (W) TRANSPOSE
AH = notes to transpose (if bit 7 set, transpose down)
------------------------------------------------------------------------------
AL==04h (W) PITCH BEND
new_global_pitch = global_pitch * BX / 1000;
------------------------------------------------------------------------------
AL==05h (W) SET PITCH
BX = global pitch
------------------------------------------------------------------------------
AL==06h (W) SET GLOBAL TEMPO
BX = new global tempo
------------------------------------------------------------------------------
AL==07h (W) FORCE TRACKJOY TO PLAY A PATTERN
AH = pattern to play (0 = first)
------------------------------------------------------------------------------
AL==08h (W) JUMP ROW
AH = row to jump to in current pattern (0 = first)
------------------------------------------------------------------------------
AL==09h (W) END "P" COMMAND POLLING
If TRACKJOY is polling for keyboard input (invoked by the
"P" pattern command), issuing this command will make TRACKJOY
continue to play the current pattern.
*** NOTE: This command is read from AL==1Eh, *NOT* AL==19h!
------------------------------------------------------------------------------
AL==20h (W) PLAY NOTE
AH = number of sample
BL = note
BH = GUS channel to play through
==============================================================================
READ COMMANDS 10h - 1Fh, 30h
==============================================================================
AL==10h (R) MUSIC CONTROL
If AH bit 0 is OFF, music is stopped
If TRACKJOY is running, BL == 'T' (54h) and BH == 'J' (4Ah)
CL = minor version number
CH = major version number
If DL bit 0 is ON, Trackjoy is paused
------------------------------------------------------------------------------
AL==11h (R) MASTER VOLUME
AH = master volume
------------------------------------------------------------------------------
AL==12h (R) CHANNEL CONTROL
(w) AH = number of channel
BL = 1 for a short period, if a note was turned on
BH = state of voice (1 = GUS is playing voice, 0 = stopped)
CL = state of channel (1 means muted)
------------------------------------------------------------------------------
AL==13h (R) TRANSPOSE
AH = semitones transposed (if bit 7 set, transposed down)
------------------------------------------------------------------------------
AL==14h (RESERVED, Pitch Bend can't be read. Use AL==15h instead)
------------------------------------------------------------------------------
AL==15h (R) READ PITCH
BX = global pitch
------------------------------------------------------------------------------
AL==16h (R) READ GLOBAL TEMPO
BX = global tempo
------------------------------------------------------------------------------
AL==17h (R) READ CURRENT PATTERN AND ORDER
AH = current pattern (0 = first)
BX:CX points to order string (128 bytes)
DL = current order
------------------------------------------------------------------------------
AL==18h (R) READ CURRENT ROW
AH = current row in pattern (0 = first)
BL = rows in current pattern
------------------------------------------------------------------------------
AL==19h (R) GET "sampleinfo" STRUCTURE ARRAY ADDRESS
struct sampleinfo sample[SAMPLES];
BX:CX equals &sample[0]
------------------------------------------------------------------------------
AL==1Ah (R) GET "gdram" STRUCTURE ADDRESS
struct gus_dram gdram;
BX:CX equals &gdram
------------------------------------------------------------------------------
AL==1Bh (R) GET NAME ASCIIZ ADDRESS
char name[80];
BX:CX equals &name
------------------------------------------------------------------------------
AL==1Ch (R) GET COMPOSER ASCIIZ ADDRESS
char composer[80];
BX:CX equals &composer
------------------------------------------------------------------------------
AL==1Dh (R) GET COMMENT ASCIIZ ADDRESS
char comment[80];
BX:CX equals &comment
------------------------------------------------------------------------------
AL==1Eh (R) CHECK PATTERN POLLING STATE
If AH==1, TRACKJOY is waiting for a interrupt with AL==09h
to continue with the current pattern. This state is invoked
with the "P" pattern command.
*** NOTE: This command is written to AL==09h, *NOT* AL=0Eh!
------------------------------------------------------------------------------
AL==1Fh (R) READ ERROR LOG
If AH != 0, TRACKJOY has an error to report
BX:CX points to the error message string
------------------------------------------------------------------------------
AL==30h (R) READ TIMER
BX:CX = (unsigned long) timer ticks from start of play
DX = (unsigned int) timer frequency
------------------------------------------------------------------------------
This is the format of the SAMPLEINFO structure. It controls the audio
samples TRACKJOY uses as instruments.
*** NOTE: The constant SAMPLES = 64.
struct sampleinfo { /* sample information */
char name[30]; /* sample description */
char file[13]; /* sample filename */
char type; /* file type (16/PC8/A8) flag */
char playmode; /* this is what's actually squirted into the GUS */
char acd; /* allocated flag */
long loopbeg; /* loop beginning */
long loopend; /* loop end */
long length; /* sample length (bytes) */
long gusoff; /* offset in GUS memory */
int freq; /* sample frequency */
unsigned vol; /* sample volume */
unsigned pad; /* padding */
};
Storage definition in TRACKJOY.C:
struct sampleinfo sample[SAMPLES];
This is the format of the GUS_DRAM structure:
struct gus_dram { /* memory control block */
unsigned long used; /* how much memory is allocated */
unsigned long beg[SAMPLES]; /* beginning of a block */
unsigned long length[SAMPLES]; /* length of a block */
char stat[SAMPLES]; /* status. 0 = empty, 1 = allocated,
2 = free */
int c; /* number of blocks */
};
*** NOTE: Status 0 (empty) always means the free hunk of memory from
the end of the last allocated block to the end of memory.
Status 1 means the block in use, and status 2 means the
block has been freed, and can be re-used. Status 2 blocks
only exist before allocated blocks of memory. (A Status 2
block at the end of allocated memory is always converted to
status 0 when the block is freed.)
Storage definition in TRACKJOY.C:
struct gus_dram gdram[4];
Each gdram in the above array is for a 256k Ultrasound memory bank.