/********************************************************************* * Lossless 8-bit audio compression utility * ( Using Elias Gamma' codes ) * Created: 20.08.2001 * Modified: 23.08.2001 * * Usage: * Encode 8-bit unsigned raw data: acom e infile outfile * Decode: acom d infile outfile * ********************************************************************/ #include #include /*----- Forward declarations ---------------------------------------*/ void PutBits(FILE* f, unsigned long bits, int num_bits); unsigned long GetBits(FILE* f, int num_bits); int NumBits(unsigned long n); void PutEliasCode(FILE* f, int n); int GetEliasCode(FILE* f); void Encode(FILE* in, FILE* out); void Decode(FILE* in, FILE* out); void PrintUsage(void); /*------------------------------------------------------------------*/ int main(int argc, char* argv[]) { if (argc != 4) { PrintUsage(); } else { const char* sw = argv[1]; const char* infile = argv[2]; const char* outfile = argv[3]; if (strcmp(sw, "e") == 0 || strcmp(sw, "d") == 0) { FILE* in = fopen(infile, "rb"); if (in != NULL) { FILE* out = fopen(outfile, "wb"); if (out != NULL) { if (strcmp(sw, "e") == 0) Encode(in, out); else if (strcmp(sw, "d") == 0) Decode(in, out); fclose(out); } else printf("Error: can't create %s\n", outfile); fclose(in); } else printf("Error: can't open %s\n", infile); } else printf("Error: invalid switch '%s'\n", sw); } return 0; } /*------------------------------------------------------------------*/ void PutBits(FILE* f, unsigned long bits, int num_bits) { static unsigned char buffer; static int bits_in_buffer = 0; static const unsigned char MAX_BITS = sizeof(bits) << 3; if (num_bits != -1) { bits <<= MAX_BITS - num_bits; while (num_bits != 0) { if (bits_in_buffer == 8) { putc(buffer, f); bits_in_buffer = 0; } buffer = (unsigned char)(buffer << 1 | bits >> (MAX_BITS - 1)); bits <<= 1; --num_bits; ++bits_in_buffer; } } else { /* Flush */ if (bits_in_buffer != 0) fputc(buffer << (8 - bits_in_buffer), f); } } /*------------------------------------------------------------------*/ unsigned long GetBits(FILE* f, int num_bits) { static unsigned char buffer; static int bits_in_buffer = 0; unsigned long bits = 0; while (num_bits != 0) { if (bits_in_buffer == 0) { buffer = (unsigned char)getc(f); bits_in_buffer = 8; } bits = bits << 1 | buffer >> 7; buffer <<= 1; --num_bits; --bits_in_buffer; } return bits; } /*------------------------------------------------------------------*/ int NumBits(unsigned long n) { const int MAX_BITS = sizeof(n) << 3; int num_bits = MAX_BITS; while ((n & (1 << (MAX_BITS - 1))) == 0 && num_bits != 0) { n <<= 1; --num_bits; } return num_bits; } /*------------------------------------------------------------------*/ void PutEliasCode(FILE* f, int n) { int num_bits = NumBits(n); PutBits(f, 0, num_bits); PutBits(f, 1, 1); PutBits(f, n - 1, num_bits); } /*------------------------------------------------------------------*/ int GetEliasCode(FILE* f) { int num_bits = 0; while (GetBits(f, 1) == 0) ++num_bits; return num_bits == 0 ? 0 : (int)GetBits(f, num_bits) + 1; } /*------------------------------------------------------------------*/ void Encode(FILE* in, FILE* out) { const int head_bits = 5; int prev_ch = 0; putc(head_bits, out); for (;;) { int delta, head, ch = getc(in); if (ch == EOF) break; delta = ch > prev_ch ? (ch - prev_ch) << 1 : (prev_ch - ch) << 1 | 1; head = delta >> (9 - head_bits); prev_ch = ch; PutEliasCode(out, head); PutBits(out, delta, 9 - head_bits); } /* EOF marker */ PutEliasCode(out, 1 << head_bits); /* Flush */ PutBits(out, 0, -1); } /*------------------------------------------------------------------*/ void Decode(FILE* in, FILE* out) { int prev_ch = 0, head_bits = getc(in); for (;;) { int delta, ch, head = GetEliasCode(in); if (head == 1 << head_bits) break; delta = (head << (9 - head_bits)) | (int)GetBits(in, 9 - head_bits); delta = delta & 1 ? -(delta >> 1) : (delta >> 1); ch = prev_ch + delta; putc(ch, out); prev_ch = ch; } } /*------------------------------------------------------------------*/ void PrintUsage(void) { puts("Usage:\n" "\tEncode 8-bit unsigned raw data: acom e infile outfile\n" "\tDecode: acom d infile outfile"); }