Released on issue 68 of Fred disk magazine, spring 1996.
Updated 24/2/98 to v2.01 (bugfix)
"Excellent" - Stefan Drissen
Programmed by Andrew Collier. This compressor is intended mainly for screens, but can be used to compress any code, provided that the compressed and uncompressed code can be in memory simultaneously. The algorithm uses Huffman encoding and Run-length compression. The compressor is fully integrated into Basic, and there is an on-screen progress indicator during the compression of memory areas. Multiple screens can be grouped into blocks automatically.
Technical info in italics
This program directly calls some ROM routines, and has been tested with ROM version 3.0. If your sam has a clone ROM or a later version then the program should function correctly.If not then a crash may be caused; a warning message will be displayed when the program is installed.
Installing the compressor code
Load the code at the start of any page (>0); ie at an address which is a multiple of 16384, 32768 or higher; and execute once.
Eg. LOAD "MNEMOcomp" CODE 81920 : CALL 81920
Providing that sufficient memory is available, code will be installed into the system heap and the highest available free page. This page number is USR's return value, which is also included on-screen in the installation message. It is, if necessary, possible to force installation into a specified page: eg CALL 81920,28
A new token is now valid: COMPRESS (You may type COMP. as shorthand) This is used as part of a command or function.
Compressing a screen
The code always compresses the currently displayed screen and palette. When you compress the first screen, you must always supply an address at which the result is to be stored. eg COMP. SCREEN AT 98304
The screen will turn black, there will be a little flickering, and several seconds later the picture will reappear. The function COMPRESS LENGTH will give the length of this screen. To compress a second screen, to be viewed immediately after the first, do not specify an address. Simply type instead: COMP. SCREEN
The function COMPRESS LENGTH always gives the total length of all screens which have been compressed together (It is reset when a new destination start address is given.) Memory restiction is the only limit to the number of screens which may be compressed in a block. When all screens have been compressed,save the code.
eg SAVE "screenblok" code 98304, COMP. LENGTH
Uncompressing a screen
Files may be decompressed either from the COMPRESSing program, or from the seperate MNEMexpand file.
It is necessary to CALL the code which has been installed :-
address = 16384*(page+1)
where page is the number given when the code was installed. To decompress the first (or only) screen in a block, CALL address,data_addr. To decompress subsequent screens, CALL address. Note that although VMPR (which controls screen mode) is changed temporarily, BASIC will not always respond to any changes. Particularly if the command is entered from the editor line, a decompression should be followed by a pause.
This highly space-optimised program fits snugly into two disk sectors, and is the only file which necessarily needs to be included with compressed data. It can be loaded at the start of any page (>0) and uses 8K of that page. Screens and screen blocks are decompressed with the command:
If a block contains only one screen then this screen is decompressed and displayed, and control returns immediately to basic. If, on the other hand, a block contains many screens then all the screens are decompressed and displayed in order, with a pause between each for the user to press a key. Two screens are used, so one screen may be viewed while the other is being decompressed.
Compressing an area of memory
It generally must be arranged that the original data, the compressor and the compressed code are in memory seperately at the same time. (This is unlikely to be a problem unless the file is very large, in which case another compressor may be a better solution. See algorithm notes, below.)
The command takes the form:
COMPRESS start_addr TO end_addr AT destination_addr
The start and end values are inclusive. During compression, the screen is switched off to increase clock speed. However, at the bottom of the screen, some indicators are made visible. Compression takes place in three stages.
When this is complete, COMPRESS LENGTH again gives the number of bytes used in the compressed file. The file can be decompressed from either the Compressor or MNEMexpand code, with:
A Note on Compression Algorithms
Every data compression technique has its own strengths and weaknesses. The huffman algorithm optimises frequently occurring bytes by giving them codes less than eight bits long. This program is recommended mainly for use with with screens, and has beaten its known competitors for space in the vast majority of tested images. The algorithm works at the cost of speed - treating a file as a sequence of bits is far more difficult thanas a sequence of bytes; it can be somewhat slower than for example, Rumsoft's Imploder, which optimises commonly occurring sequences of bytes. One of that program's biggest advantages is that the original data needn't be kept intact throughout decompression, and thus it is able to handle much larger files than my program.
Decompression speed is an important factor to consider when choosing a compression system to use. The MNEMexpand file keeps interrupts enabled, so that screens which use palette line may be viewed properly. The compressor program does not, and is therefore able to use the stack pointer during decompression, resulting in a 50% increase in speed. The imploder is a little faster and sometimes more efficient, but my program has the advantage that I have included decompression source code - an adventurous coder might like to include some intro effects to help pass the time while the main demo decompresses... Remember that various algorithms will have different levels of success on different files, so trial and error with various systems is possibly the only way to ensure greatest efficiency.