| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- /*
- ** Command & Conquer Red Alert(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /****************************************************************************
- *
- * C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
- *
- *----------------------------------------------------------------------------
- *
- * FILE
- * Audzap.c
- *
- * DESCRIPTION
- * Lossy audio compression. (32-Bit protected mode)
- *
- * PROGRAMMER
- * Joe L. Bostic
- *
- * DATE
- * January 26, 1995
- *
- *----------------------------------------------------------------------------
- *
- * PUBLIC
- * AudioZap - Compress audio sample data.
- *
- ****************************************************************************/
- #include <stdio.h>
- #include <mem.h>
- #include "compress.h"
- /*---------------------------------------------------------------------------
- * PRIVATE DECLARATIONS
- *-------------------------------------------------------------------------*/
- #define MIN(a,b) (((a)<(b)) ? (a) : (b))
- #define MAX(a,b) (((a)>(b)) ? (a) : (b))
- typedef enum {
- CODE_2BIT, /* Bit packed 2 bit delta. */
- CODE_4BIT, /* Nibble packed 4 bit delta. */
- CODE_RAW, /* Raw sample. */
- CODE_SILENCE /* Run of silence. */
- } SCodeType;
- char _2bitencode[5] = {
- 0,1,2,3
- };
- long _2bitdecode[4] = {
- -2,-1,0,1
- };
- char _4bitencode[19] = {
- 0,1,2,2,3,4,5,6,7,(8),
- 8,9,10,11,12,13,13,14,15
- };
- long _4bitdecode[16] = {
- -9,-8,-6,-5,-4,-3,-2,
- -1,0,1,2,3,4,5,6,8
- };
- /****************************************************************************
- *
- * NAME
- * AudioZap - Compress audio sample data.
- *
- * SYNOPSIS
- * Size = AudioZap(Source, Dest, Size)
- *
- * long AudioZap(void *, void *, long);
- *
- * FUNCTION
- * NOTE - If the compressed size is equal to or greater than the original
- * size then the data could not be compressed and the uncompressed data
- * should be written.
- *
- * INPUTS
- * Source - Pointer to buffer containing audio sample data.
- * Dest - Pointer to buffer to put encoded data.
- * Size - Number of bytes to compress.
- *
- * RESULT
- * Size - Size in bytes of encoded data.
- *
- ****************************************************************************/
- long AudioZap(void *source, void *dest, long size)
- {
- unsigned char *s = (unsigned char *)source;
- unsigned char *d = (unsigned char *)dest;
- long delta;
- unsigned long previous = 0x80;
- long outcount = 0;
- unsigned char *s4;
- unsigned long p4;
- long max4;
- unsigned char *lastraw = 0;
- long osize = size;
- unsigned long i;
- unsigned long dd;
- /* Reduce very small amplitudes to silence. Usually a rather large
- * portion of a sample is hovering around the silence value. This is
- * due, in part, to the artifacting of the sample process. These low
- * amplitudes are not audible.
- */
- max4 = size;
- s = (unsigned char *)source;
- while (size > 0 && outcount < osize) {
- /* First check for runs of zero deltas. If a run of at least
- * any can be found, then output it.
- */
- s4 = s;
- max4 = MIN(63 + 1, size);
- for (i = 0; i < max4; i++) {
- if (previous != *s4++)
- break;
- }
- /* When there is a code transition, terminate any run of raw
- * samples.
- */
- if (i > 2) {
- lastraw = 0;
- *d++ = ((i - 1)|(CODE_SILENCE << 6));
- outcount++;
- s += i;
- size -= i;
- continue;
- }
- /* If there are fewer than 4 samples remaining, then using delta
- * compression is inefficient. Just drop into the raw routine
- */
- if (size > 4) {
- s4 = s;
- p4 = previous;
- /* Find out the number of lossless 2 bit deltas available. These
- * deltas are always present in quads. The compressed code is
- * the delta quad count followed by the deltas in bit packed bytes.
- */
- max4 = MIN(64L * 4L + 4L + 4L, size);
- for (i = 0; i < max4; i++) {
- delta = (((int)*s4++) - p4);
- if ((delta < -2) || (delta > 1)) {
- break;
- }
- p4 += _2bitdecode[_2bitencode[delta + 2]];
- if (((signed)p4) < 0) {
- p4 = 0;
- }
- if (((signed)p4) > 255) {
- p4 = 255;
- }
- }
- i >>= 2; // Delta 2 always occur in quads -- force this.
- /* If there is the minimum benificial number of delta 2s available,
- * then compress them.
- */
- if (i) {
- /* When there is a code transition, terminate any run of raw
- * samples.
- */
- lastraw = 0;
- /* Output the delta 4 pair count. This is the number of pairs
- * minus the 'free' two pairs already assumed to be there.
- */
- i = MIN(i, (63 + 1));
- *d++ = ((i - 1)|(CODE_2BIT << 6));
- outcount++;
- for (dd = 0; dd < i; dd++) {
- int delta1, delta2, delta3, delta4;
- delta1 = _2bitencode[((((int)*s++) - previous) + 2)];
- previous += _2bitdecode[delta1];
- if (((signed)previous) < 0) {
- previous = 0;
- }
- if (((signed)previous) > 255) {
- previous = 255;
- }
- size--;
- delta2 = _2bitencode[((((int)*s++) - previous) + 2)];
- previous += _2bitdecode[delta2];
- if (((signed)previous) < 0) {
- previous = 0;
- }
- if (((signed)previous) > 255) {
- previous = 255;
- }
- size--;
- delta3 = _2bitencode[((((int)*s++) - previous) + 2)];
- previous += _2bitdecode[delta3];
- if (((signed)previous) < 0) {
- previous = 0;
- }
- if (((signed)previous) > 255) {
- previous = 255;
- }
- size--;
- delta4 = _2bitencode[((((int)*s++) - previous) + 2)];
- previous += _2bitdecode[delta4];
- if (((signed)previous) < 0) {
- previous = 0;
- }
- if (((signed)previous) > 255) {
- previous = 255;
- }
- size--;
- *d++ = ((delta4 << 6)|(delta3 << 4)|(delta2 << 2)|delta1);
- outcount++;
- }
- continue;
- } else {
- s4 = s;
- p4 = previous;
- /* Find out the number of lossless 4 bit deltas follow. These
- * deltas are always present in pairs. The compressed code is
- * the delta pair count followed by the deltas in nibble packed
- * bytes.
- */
- max4 = MIN(64L * 2L + 4L + 4L, size);
- for (i = 0; i < max4; i++) {
- delta = (((int)*s4++) - p4);
- if (delta < -9 || delta >= 9) {
- break;
- }
- p4 += _4bitdecode[_4bitencode[(delta + 9)]];
- if (((signed)p4) < 0) {
- p4 = 0;
- }
- if (((signed)p4) > 255) {
- p4 = 255;
- }
- }
- i >>= 1; // Delta 4 always occur in pairs -- force this.
- /* If there is the minimum benificial number of delta 4s available,
- * then compress them.
- */
- if (i) {
- /* When there is a code transition, terminate any run of raw
- * samples.
- */
- lastraw = 0;
- /* Output the delta 4 pair count. This is the number of pairs
- * minus the 'free' two pairs already assumed to be there.
- */
- i = MIN(i, (63 + 1));
- *d++ = ((i - 1)|(CODE_4BIT << 6));
- outcount++;
- for (dd = 0; dd < i; dd++) {
- int delta1, delta2;
- delta1 = _4bitencode[((((int)*s++) - previous) + 9)];
- previous += _4bitdecode[delta1];
- if (((signed)previous) < 0) {
- previous = 0;
- }
- if (((signed)previous) > 255) {
- previous = 255;
- }
- size--;
- delta2 = _4bitencode[((((int)*s++) - previous) + 9)];
- previous += _4bitdecode[delta2];
-
- if (((signed)previous) < 0) {
- previous = 0;
- }
- if (((signed)previous) > 255) {
- previous = 255;
- }
- size--;
- *d++ = ((delta2 << 4)|(delta1 & 0x0F));
- outcount++;
- }
- continue;
- }
- }
- }
- /* Raw output since deltas were unsuccessful. If this is a run
- * of raw output, then merely tack it onto the run rather than
- * create a new code sequence.
- */
- if (lastraw) {
- *lastraw = ((*lastraw) + 1);
- /* There is only so much a run code can accomodate. If the limit
- * has been reached, then terminate this code. A new one will be
- * created if necessary.
- */
- if ((*lastraw & 0x1F) == 0x1F) {
- lastraw = 0;
- }
- } else {
-
- /* If there is no current raw dump of samples, then check to see if
- * this sample can fit into a 5 bit delta. If it can, then store
- * it as such as a parasite to the "raw" code. This will save a byte
- * for any stray 5 bit deltas that happen along. It is expected that
- * this is more frequent than 6 or more bit deltas that would necessitate
- * the use of the RAW code.
- */
- delta = (((int)*s) - previous);
- if ((delta >= -16) && (delta <= 15)) {
- lastraw = 0;
- *d++ = ((CODE_RAW << 6)|0x20|(delta & 0x1F));
- outcount++;
- previous = *s++;
- size--;
- continue;
- } else {
- lastraw = d;
- *d++ = (CODE_RAW << 6);
- outcount++;
- }
- }
- *d++ = previous = *s++;
- size--;
- outcount++;
- }
- /* Check to see if the compression process actually resulted in smaller
- * data size. In some cases, the 'compressed' data is actually larger. In
- * this case, just output the raw frame. If the compressed and actual frame
- * size match, then it is presumed that no compression occurs.
- */
- if (outcount >= osize) {
- memcpy(dest, source, (size_t)osize);
- outcount = osize;
- }
- return(outcount);
- }
|