ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ 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] 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 bytes of sample data, whether 8- or 16-bit. 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 , or ) 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> 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 and height of . 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 ... 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 ------------------------------------------------------------------------------ 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.