Skip to content

Instantly share code, notes, and snippets.

@iamgreaser
Created April 24, 2014 03:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iamgreaser/11240698 to your computer and use it in GitHub Desktop.
Save iamgreaser/11240698 to your computer and use it in GitHub Desktop.
broken audio codec implementation (curva)
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
/*
format:
int8_t block_delta_table[CURVA_TABLE_SIZE][CURVA_RUN_SIZE];
uint8_t data[CURVA_BLOCK_SIZE/CURVA_RUN_SIZE];
decoding:
uint8_t v = 0x80;
for(i = 0; i < CURVA_BLOCK_SIZE/CURVA_RUN_SIZE; i++)
for(j = 0; j < CURVA_RUN_SIZE; j++)
outdata[k++] = v = SATURATE_ADD_U8(v, block_delta_table[data[i]][j]);
*/
// Block size is in input bytes, so 32KB in -> 4KB out for a run size of 8
#define CURVA_RUN_SIZE 8
#define CURVA_TABLE_SIZE 256
#define CURVA_BLOCK_SIZE (1<<14)
#define CURVA_OUT_SIZE (CURVA_TABLE_SIZE*CURVA_RUN_SIZE + (CURVA_BLOCK_SIZE/CURVA_RUN_SIZE))
int16_t cb_delta[CURVA_BLOCK_SIZE];
int16_t cb_cmotion[CURVA_BLOCK_SIZE/CURVA_RUN_SIZE];
int32_t cb_cturbulence[CURVA_BLOCK_SIZE/CURVA_RUN_SIZE];
int16_t cb_motion[CURVA_TABLE_SIZE];
int32_t cb_turbulence[CURVA_TABLE_SIZE];
int8_t cb_table[CURVA_TABLE_SIZE][CURVA_RUN_SIZE];
// WARNING: THIS FUNCTION IS NOT THREAD-SAFE
int curva_encode(uint8_t *indata, int inlen, uint8_t *outdata)
{
int i, j, k;
if(inlen > CURVA_BLOCK_SIZE)
inlen = CURVA_BLOCK_SIZE;
// Convert data into delta format
uint8_t ov = 0x80;
for(i = 0; i < inlen; i++)
{
cb_delta[i] = (int16_t)(indata[i]) - (int16_t)ov;
ov = indata[i];
}
for(; i < CURVA_BLOCK_SIZE; i++)
cb_delta[i] = 0;
// Clamp deltas to signed 8-bit range
int32_t acc = 0;
for(i = 0; i < CURVA_BLOCK_SIZE; i++)
{
cb_delta[i] += acc;
acc = 0;
if(cb_delta[i] > 127)
{
acc = cb_delta[i];
cb_delta[i] = 127;
acc -= cb_delta[i];
} else if(cb_delta[i] < -127) {
acc = cb_delta[i];
cb_delta[i] = -127;
acc -= cb_delta[i];
}
}
// Calculate motion + turbulence for each block
for(i = 0; i < CURVA_BLOCK_SIZE/CURVA_RUN_SIZE; i++)
{
int16_t macc = 0;
int32_t tacc = 0;
acc = 0;
for(j = 0; j < CURVA_RUN_SIZE; j++)
{
int32_t tv = cb_delta[i*CURVA_RUN_SIZE + j];
macc += tv;
tacc += tv*tv;
}
cb_cmotion[i] = macc;
cb_cturbulence[i] = tacc;
}
// Create block table
// TODO: Not be a slack bastard about this, and USE AN ACTUAL ALGORITHM.
for(i = 0; i < CURVA_TABLE_SIZE; i++)
{
int ridx = i * CURVA_BLOCK_SIZE/CURVA_RUN_SIZE/CURVA_TABLE_SIZE;
for(j = 0; j < CURVA_RUN_SIZE; j++)
outdata[i*CURVA_RUN_SIZE + j] = cb_table[i][j] = cb_delta[ridx*CURVA_RUN_SIZE + j];
cb_motion[i] = cb_cmotion[ridx];
cb_turbulence[i] = cb_cturbulence[ridx];
}
// Now compress!
int16_t lout = 0x80;
int16_t luse = 0x80;
for(i = 0; i < CURVA_BLOCK_SIZE/CURVA_RUN_SIZE; i++)
{
// Select best block for the job
int16_t bm = cb_cmotion[i] - (lout - luse);
int16_t bt = cb_cturbulence[i];
int best_idx = 0;
int32_t best_weight = 256*256*2;
int16_t best_motion = cb_motion[best_idx];
//fprintf(stderr, "homk %i\n", i);
for(j = 0; j < CURVA_TABLE_SIZE/4; j++)
{
/*
int dm = cb_motion[j] - bm;
int dt = cb_turbulence[j] - bm;
int32_t dw = dm*dm + dt;
*/
int32_t dw = 0;
for(k = 0; k < CURVA_RUN_SIZE; k++)
{
int32_t diff = cb_delta[i*CURVA_RUN_SIZE + k] - (int32_t)cb_table[j][k];
dw += diff*diff;
}
if(dw < best_weight)
{
best_weight = dw;
best_idx = j;
}
}
// Write and calculate
outdata[CURVA_TABLE_SIZE*CURVA_RUN_SIZE + i] = best_idx;
//fprintf(stderr, "mot %i %i %i %i %i\n", best_idx, lout, luse, cb_motion[best_idx], bm);
lout += cb_motion[best_idx];
luse += bm;
if(lout > 255) lout = 255;
if(lout < 0 ) lout = 0 ;
if(luse > 255) luse = 255;
if(luse < 0 ) luse = 0 ;
}
return inlen;
}
void curva_decode(uint8_t *indata, uint8_t *outdata)
{
int i,j,k;
int16_t v = 0x80;
for(i = 0, k = 0; i < CURVA_BLOCK_SIZE/CURVA_RUN_SIZE; i++)
{
int idx = indata[CURVA_TABLE_SIZE*CURVA_RUN_SIZE + i];
for(j = 0; j < CURVA_RUN_SIZE; j++, k++)
{
v += (int8_t)(indata[CURVA_RUN_SIZE*idx + j]);
if(v > 255) v = 255;
if(v < 0 ) v = 0 ;
//fprintf(stderr, "dec %i %i\n", v, idx);
outdata[k++] = v;
}
}
}
uint8_t main_bufin[CURVA_BLOCK_SIZE];
uint8_t main_bufout[CURVA_OUT_SIZE];
int read_all(int fd, void *buf, int len)
{
int alen = 0;
while(len > 0)
{
int l = read(fd, buf, len);
if(l == -1) return -1;
if(l == 0) return alen;
alen += l;
buf += l;
len -= l;
}
return alen;
}
int write_all(int fd, void *buf, int len)
{
int alen = 0;
while(len > 0)
{
int l = write(fd, buf, len);
if(l == -1) return -1;
if(l == 0) return alen;
alen += l;
buf += l;
len -= l;
}
return alen;
}
int main(int argc, char *argv[])
{
for(;;)
{
int bytesin = read_all(STDIN_FILENO, main_bufin, CURVA_BLOCK_SIZE);
curva_encode(main_bufin, CURVA_BLOCK_SIZE, main_bufout);
memset(main_bufin, 0, CURVA_BLOCK_SIZE);
curva_decode(main_bufout, main_bufin);
write_all(STDOUT_FILENO, main_bufin, CURVA_BLOCK_SIZE);
//fprintf(stderr, "[%i %i]\n", CURVA_BLOCK_SIZE, bytesin);
if(bytesin != CURVA_BLOCK_SIZE)
break;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment