ref: b96d21bfc2516311ff6b5e6af3d6d0ae5ba0cae2
dir: /korg_syro_comp.c/
/************************************************************************
SYRO for volca sample
comprss PCM
***********************************************************************/
#include <stdlib.h>
#include <string.h>
#include "korg_syro_type.h"
#include "korg_syro_volcasample.h"
#include "korg_syro_func.h"
#include "korg_syro_comp.h"
typedef struct {
const uint8_t *ptr;
uint32_t NumOfSample;
int bitlen_eff;
Endian SampleEndian;
uint16_t sum;
uint16_t padding;
} ReadSample;
typedef struct {
uint8_t *ptr;
int BitCount;
int ByteCount;
} WriteBit;
/*-----------------------------------------------------------------------------
Write Bit
** Update pwp member(ptr, BitCount, ByteCount)
-----------------------------------------------------------------------------*/
static void SyroComp_WriteBit(WriteBit *pwp, uint32_t dat, int bit)
{
//-- write bit as big-endian format.(MSB->LSB) --
dat <<= (32-bit);
dat >>= pwp->BitCount;
for (;;) {
if (pwp->BitCount) {
*pwp->ptr |= (uint8_t)(dat>>24);
} else {
*pwp->ptr = (uint8_t)(dat>>24);
}
if ((pwp->BitCount + bit) >= 8) {
bit -= (8 - pwp->BitCount);
pwp->BitCount=0;
pwp->ByteCount++;
pwp->ptr++;
dat <<= 8;
} else {
pwp->BitCount += bit;
bit = 0;
}
if (!bit) {
break;
}
}
}
/*-----------------------------------------------------------------------------
Read PCM (fixed to 16bit)
-----------------------------------------------------------------------------*/
static int32_t SyroComp_GetPcm(ReadSample *prp)
{
int32_t dat;
if (prp->SampleEndian == LittleEndian) {
dat = (int32_t)((int8_t)(prp->ptr[1]));
dat <<= 8;
dat |= (int32_t)(*prp->ptr);
prp->ptr += 2;
} else {
dat = (int32_t)((int8_t)(*prp->ptr++));
dat <<= 8;
dat |= (int32_t)(*prp->ptr++);
}
/*----- convert, 16Bit -> specified bit ----*/
if (prp->bitlen_eff < 16) {
dat /= (1 << (16 - prp->bitlen_eff)); //replace from dat >>= (16 - prp->bitlen_eff);
prp->sum += (uint16_t)(dat << (16 - prp->bitlen_eff));
} else {
prp->sum += (uint16_t)dat;
}
return dat;
}
/*-----------------------------------------------------------------------------
Generate bit-map, store to map_buffer
-----------------------------------------------------------------------------*/
static void SyroComp_MakeMapBuffer(uint8_t *map_buffer, ReadSample *prp, int *pBitBase, int nBitBase, int type)
{
int i;
uint32_t mcnt;
int32_t dat[4];
int32_t datn;
int bnum;
memset(map_buffer, 0, VOLCASAMPLE_COMP_BLOCK_LEN);
bnum = 0;
mcnt = 0;
map_buffer[mcnt++] = (uint8_t)prp->bitlen_eff; /* fix to full-bit 1st~3rd */
map_buffer[mcnt++] = (uint8_t)prp->bitlen_eff;
map_buffer[mcnt++] = (uint8_t)prp->bitlen_eff;
if (mcnt >= prp->NumOfSample) {
return;
}
dat[3] = SyroComp_GetPcm(prp);
dat[2] = SyroComp_GetPcm(prp);
dat[1] = SyroComp_GetPcm(prp);
for (;;) {
dat[0] = SyroComp_GetPcm(prp);
datn = dat[0];
if (type) {
datn -= (dat[1]*2 - dat[2]);
}
if (datn < 0) {
datn = -datn;
}
for (i=0; i<nBitBase; i++) {
bnum = pBitBase[i];
if (datn < ( 1 << (bnum-1))) break;
}
if (i == nBitBase) {
bnum = prp->bitlen_eff;
}
map_buffer[mcnt++] = (uint8_t)bnum;
if (mcnt == prp->NumOfSample) {
break;
}
dat[3] = dat[2];
dat[2] = dat[1];
dat[1] = dat[0];
}
}
/*-----------------------------------------------------------------------------
convert bit-map in map_buffer.
for example, bit=4,4,1,4 -> bit 4,4,4,4
-----------------------------------------------------------------------------*/
static void SyroComp_MakeMap_BitConv(uint8_t *map_buffer, int num_of_sample, int bitlen)
{
int i, j;
int dat, dat1;
int datlo, dathi, datuse;
int st;
int pls, min;
for (i=0; i<bitlen; i++) {
st = -1;
for (j=0; j<(num_of_sample+1); j++) {
dat = (j<num_of_sample) ? map_buffer[j] : 0;
if (dat==i) {
if (st==-1) {
st=j;
}
} else {
if (st!=-1) {
dat1 = st ? map_buffer[st-1] : 0;
if (dat<dat1) {
datlo = dat;
dathi = dat1;
} else {
datlo = dat1;
dathi = dat;
}
if (dathi > i) {
datuse = dathi;
if (datlo > i) {
datuse = datlo;
}
pls = (datuse-i) * (j-st);
min = 2 + i;
if (datuse==bitlen) {
min++;
}
if (dathi==datlo) {
min += 2 + datlo;
if (datlo==bitlen) {
min++;
}
}
if (min>=pls) {
for (; st<j; st++) {
map_buffer[st] = (uint8_t)datuse;
}
}
}
st = -1;
}
}
}
}
}
/*-----------------------------------------------------------------------------
Get compressed size form map_buffer
-----------------------------------------------------------------------------*/
static int SyroComp_GetCompSizeFromMap(uint8_t *map_buffer, ReadSample *prp, int type)
{
int i, pr, bit, prbit;
int32_t dat, datlim;
int bitlen;
int32_t dath[4];
bitlen = prp->bitlen_eff;
datlim = -(1<<(bitlen-1));
dath[0] = 0;
dath[1] = 0;
dath[2] = 0;
dath[3] = 0;
prbit = map_buffer[0];
pr = 16 + 2; // 16=BitLen(4)*4, 2=1st Header
for (i=0; i<(int)prp->NumOfSample; i++) {
dath[0] = SyroComp_GetPcm(prp);
bit = map_buffer[i];
if (bit != prbit) {
pr += prbit;
if (prbit==bitlen) {
pr++;
}
pr += 2;
prbit = bit;
}
pr += bit;
if ((prbit < bitlen) && type) {
dat = dath[0] - (dath[1]*2 - dath[2]);
} else {
dat = dath[0];
}
if (bit==bitlen && dat==datlim) {
pr++;
}
dath[3] = dath[2];
dath[2] = dath[1];
dath[1] = dath[0];
}
pr += prbit;
if (prbit==bitlen) {
pr++;
}
return pr;
}
/*-----------------------------------------------------------------------------
Make map (single type)
(prp is updated)
memo : comppcm.c-MakeMap2
-----------------------------------------------------------------------------*/
static int SyroComp_MakeMap_SingleType(uint8_t *map_buffer, ReadSample *prp, int *pBitBase, int type)
{
ReadSample rp2;
uint32_t len;
uint32_t li;
int i, j;
int BitBase[16];
int bitlen;
bitlen = prp->bitlen_eff;
/*------- make map of all bit --------*/
for (i=0; i<(bitlen-1); i++) {
BitBase[i] = i+1;
}
rp2 = *prp;
SyroComp_MakeMapBuffer(map_buffer, &rp2, BitBase, (bitlen-1), type);
SyroComp_MakeMap_BitConv(map_buffer, (int)rp2.NumOfSample, bitlen);
/*------- Check maked map and guess bit -------*/
{
int BitBaseScore[16];
int maxbit, maxsc, sc;
for (i=0; i<16; i++) {
BitBaseScore[i] = 0;
}
for (li=0; li<prp->NumOfSample; li++) {
sc = map_buffer[li];
if (sc < 16) {
BitBaseScore[sc]++;
}
}
/*-- select top 4 depth -----*/
for (i=0; i<4; i++) {
maxsc = -1;
maxbit = -1;
for (j=0; j<bitlen; j++) {
if (BitBaseScore[j] > maxsc) {
maxsc = BitBaseScore[j];
maxbit = j;
}
}
BitBase[i] = maxbit;
BitBaseScore[maxbit] = -1;
}
/*-- sort selected bit (low->high) ----*/
for (i=0; i<3; i++) {
for (j=0; j<3; j++) {
if (BitBase[j] > BitBase[j+1]) {
sc = BitBase[j];
BitBase[j] = BitBase[j+1];
BitBase[j+1] = sc;
}
}
}
}
/*-----------------------------------*/
rp2 = *prp;
SyroComp_MakeMapBuffer(map_buffer, &rp2, BitBase, 4, type);
SyroComp_MakeMap_BitConv(map_buffer, (int)prp->NumOfSample, bitlen);
rp2 = *prp;
len = (uint32_t)SyroComp_GetCompSizeFromMap(map_buffer, &rp2, type);
for (i=0; i<4; i++) {
pBitBase[i] = BitBase[i];
}
return (int)len;
}
/*-----------------------------------------------------------------------------
make map, get size
-- keep prp->ptr
-----------------------------------------------------------------------------*/
static int SyroComp_MakeMap(uint8_t *map_buffer, ReadSample *prp, int *pBitBase, int *ptype)
{
int i;
int besttype;
int len, bestlen;
int BitBase[4];
bestlen = 0;
besttype = 0;
for (i=0; i<2; i++) {
len = SyroComp_MakeMap_SingleType(map_buffer, prp, BitBase, (i*2)); // type=0 or 2
if ((!bestlen) || (len < bestlen)) {
bestlen = len;
besttype = i;
}
}
if (pBitBase && ptype) {
bestlen = SyroComp_MakeMap_SingleType(map_buffer, prp, pBitBase, (besttype*2));
*ptype = (besttype ? 2 : 0);
}
return bestlen;
}
/*-----------------------------------------------------------------------------
Compress 1 block
** Update prp
-----------------------------------------------------------------------------*/
static int SyroComp_CompBlock(uint8_t *map_buffer, uint8_t *dest, ReadSample *prp, int *pBitBase, int type)
{
int i, j, bit, prbit;
int bitlen;
int32_t dat, datlim;
int32_t dath[4];
uint8_t hd;
WriteBit wp;
int BitHead[16];
wp.ptr = dest;
wp.BitCount = 0;
wp.ByteCount = 0;
dath[0] = 0;
dath[1] = 0;
dath[2] = 0;
dath[3] = 0;
/*----- wrtie bit-base ------*/
j = 0;
for (i=0; i<16; i++) {
if (pBitBase[j]==i) {
BitHead[i] = j++;
SyroComp_WriteBit(&wp, (uint32_t)(i-1), 4);
} else {
BitHead[i] = -1;
}
}
bitlen = prp->bitlen_eff;
datlim = -(1<<(bitlen-1));
prbit = bitlen;
SyroComp_WriteBit(&wp, 3, 2);
for (i=0; i<(int)prp->NumOfSample; i++) {
dath[0] = SyroComp_GetPcm(prp);
bit = map_buffer[i];
if (bit != prbit) {
/*--- write end mark ---*/
SyroComp_WriteBit(&wp, (1<<(prbit-1)), prbit);
if (prbit==bitlen) {
SyroComp_WriteBit(&wp, 1, 1); /* add 1 bit when full-bit */
}
/*--- write this header ----*/
if (bit < bitlen) {
hd = (uint8_t)BitHead[bit];
if (bit > prbit) {
hd--;
}
} else {
hd = 3;
}
SyroComp_WriteBit(&wp, hd, 2);
prbit = bit;
}
if ((prbit < bitlen) && type) {
dat = dath[0] - (dath[1]*2 - dath[2]);
} else {
dat = dath[0];
}
SyroComp_WriteBit(&wp, (uint32_t)dat, prbit);
if ((prbit == bitlen) && (dat == datlim)) {
SyroComp_WriteBit(&wp, 0, 1);
}
dath[3] = dath[2];
dath[2] = dath[1];
dath[1] = dath[0];
}
SyroComp_WriteBit(&wp, (1<<(prbit-1)), prbit); /* EndMark */
if (prbit == bitlen) {
SyroComp_WriteBit(&wp, 1, 1); /* add 1 bit when full-bit */
}
if (wp.BitCount) {
SyroComp_WriteBit(&wp, 0, (8 - wp.BitCount));
}
return wp.ByteCount;
}
/*======================================================================
Syro Get Sample
======================================================================*/
uint32_t SyroComp_GetCompSize(const uint8_t *psrc, uint32_t num_of_sample,
uint32_t quality, Endian sample_endian)
{
ReadSample rp;
uint32_t num_of_thissample;
uint32_t allsize_byte;
uint32_t thissize_bit;
uint8_t *map_buffer;
map_buffer = malloc(VOLCASAMPLE_COMP_BLOCK_LEN);
if (!map_buffer) {
return 0;
}
rp.ptr = psrc;
rp.bitlen_eff = (int)quality;
rp.SampleEndian = sample_endian;
allsize_byte = 0;
for (;;) {
num_of_thissample = VOLCASAMPLE_COMP_BLOCK_LEN;
if (num_of_thissample > num_of_sample) {
num_of_thissample = num_of_sample;
}
rp.NumOfSample = num_of_thissample;
thissize_bit = (uint32_t)SyroComp_MakeMap(map_buffer, &rp, NULL, NULL);
if ((!thissize_bit) || (thissize_bit >= (quality * num_of_thissample))) {
//----- use liner ----
thissize_bit = (quality * num_of_thissample);
}
allsize_byte += ((thissize_bit + 7) / 8);
allsize_byte += 6; //--- for Header & CRC -----
rp.ptr += (num_of_thissample * 2);
num_of_sample -= num_of_thissample;
if (!num_of_sample) {
break;
}
}
free(map_buffer);
return allsize_byte;
}
/*=============================================================================
Compress Block
psrc = pointer to source sample.
pdest = pointer to store compressed data.
num_of_sample = number of sample.
quality = number of effective bit(8~16).
sample_endian = specific endian of source sample(LittleEndian or BigEndian).
=============================================================================*/
uint32_t SyroComp_Comp(const uint8_t *psrc, uint8_t *pdest, int num_of_sample,
int quality, Endian sample_endian)
{
ReadSample rp;
int BitBase[4];
int i;
int srccount, count;
int num_of_thissample;
int prlen;
int type;
int32_t dat;
uint8_t *map_buffer;
map_buffer = malloc(VOLCASAMPLE_COMP_BLOCK_LEN);
if (!map_buffer) {
return 0;
}
rp.bitlen_eff = quality;
rp.SampleEndian = sample_endian;
rp.ptr = psrc;
count = 0;
srccount = 0;
for (;;) {
/*------- decide block length ------*/
num_of_thissample = VOLCASAMPLE_COMP_BLOCK_LEN;
if (num_of_thissample > num_of_sample) {
num_of_thissample = num_of_sample;
}
rp.NumOfSample = (uint32_t)num_of_thissample;
rp.sum = 0;
prlen = SyroComp_MakeMap(map_buffer, &rp, BitBase, &type);
if (prlen && (prlen < (num_of_thissample*quality))) {
/*----- compressible ------*/
*pdest++ = (uint8_t)(num_of_thissample>>8) | (uint8_t)(type<<5);
*pdest++ = (uint8_t)num_of_thissample;
prlen = SyroComp_CompBlock(map_buffer, pdest+4, &rp, BitBase, type);
*pdest++ = (uint8_t)(prlen>>8);
*pdest++ = (uint8_t)prlen;
*pdest++ = (uint8_t)(rp.sum >> 8);
*pdest++ = (uint8_t)rp.sum;
count += (prlen+6);
pdest += prlen;
} else {
/*----- copy without compression ------*/
*pdest++ = (uint8_t)(0xe0 | (num_of_thissample>>8));
*pdest++ = (uint8_t)num_of_thissample;
*pdest++ = (uint8_t)(num_of_thissample>>7);
*pdest++ = (uint8_t)(num_of_thissample<<1);
{
WriteBit wb;
wb.ptr = (pdest+2);
wb.BitCount = 0;
wb.ByteCount = 0;
for (i=0; i<num_of_thissample; i++) {
dat = SyroComp_GetPcm(&rp);
SyroComp_WriteBit(&wb, (uint32_t)dat, quality);
}
if (wb.BitCount) {
SyroComp_WriteBit(&wb, 0, (8-wb.BitCount));
}
*pdest++ = (uint8_t)(rp.sum >> 8);
*pdest++ = (uint8_t)rp.sum;
prlen = wb.ByteCount;
pdest += prlen;
count += (prlen+6);
}
}
num_of_sample -= num_of_thissample;
srccount += num_of_thissample;
if (!num_of_sample) {
break;
}
}
free(map_buffer);
return (uint32_t)count;
}