Created
April 24, 2014 03:41
-
-
Save iamgreaser/11240698 to your computer and use it in GitHub Desktop.
broken audio codec implementation (curva)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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