summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <xiphmont@xiph.org>2000-04-21 16:35:41 +0000
committerMonty <xiphmont@xiph.org>2000-04-21 16:35:41 +0000
commit097027d02df14cab9f0ffe712995aa7f7f16f392 (patch)
treec3345d1845908066bb6dfe9628b6d42d6566bba2
parent3a29507ebfb9f6fbc37a2f575b49e11761ffcb8f (diff)
downloadlibvorbis-git-097027d02df14cab9f0ffe712995aa7f7f16f392.tar.gz
Incremental update:
Backed out log scale codebooks; turned out to be less than useful and too complicated. Added lattice codebooks, allow for additive and multiplicative cascading (multiplicitive cascading is what made log scale books obsolete). Monty svn path=/branches/new_acoustics_pending_merge_20000328/vorbis/; revision=341
-rw-r--r--include/vorbis/backends.h8
-rw-r--r--include/vorbis/codebook.h52
-rw-r--r--include/vorbis/codec.h11
-rw-r--r--include/vorbis/modes.h63
-rw-r--r--lib/Makefile.in13
-rw-r--r--lib/bookinternal.h12
-rw-r--r--lib/codebook.c305
-rw-r--r--lib/floor0.c52
-rw-r--r--lib/framing.c18
-rw-r--r--lib/info.c4
-rw-r--r--lib/lsp.c48
-rw-r--r--lib/mapping0.c12
-rw-r--r--lib/psy.c151
-rw-r--r--lib/psy.h8
-rw-r--r--lib/psytune.c108
-rw-r--r--lib/res0.c118
-rw-r--r--lib/sharedbook.c498
-rw-r--r--lib/sharedbook.h10
-rw-r--r--vq/Makefile.in13
-rw-r--r--vq/bookutil.c183
-rw-r--r--vq/bookutil.h3
-rw-r--r--vq/build.c102
-rw-r--r--vq/cascade.c42
-rw-r--r--vq/huffbuild.c9
-rw-r--r--vq/latticebuild.c311
-rw-r--r--vq/lspdata.c4
-rw-r--r--vq/metrics.c114
-rw-r--r--vq/partition.c88
-rw-r--r--vq/residuedata.c51
-rw-r--r--vq/residuesplit.c116
-rw-r--r--vq/run.c218
-rw-r--r--vq/train.c10
-rw-r--r--vq/vqgen.c21
-rw-r--r--vq/vqgen.h5
-rw-r--r--vq/vqsplit.c10
35 files changed, 1726 insertions, 1065 deletions
diff --git a/include/vorbis/backends.h b/include/vorbis/backends.h
index 7b4f3f03..9a989646 100644
--- a/include/vorbis/backends.h
+++ b/include/vorbis/backends.h
@@ -13,7 +13,7 @@
function: libvorbis backend and mapping structures; needed for
static mode headers
- last mod: $Id: backends.h,v 1.7.4.3 2000/04/13 04:53:03 xiphmont Exp $
+ last mod: $Id: backends.h,v 1.7.4.4 2000/04/21 16:35:38 xiphmont Exp $
********************************************************************/
@@ -66,7 +66,6 @@ typedef struct{
int order;
long rate;
long barkmap;
- unsigned char subcurve[27];
int ampbits;
int ampdB;
@@ -98,9 +97,10 @@ typedef struct vorbis_info_residue0{
int grouping; /* group n vectors per partition */
int partitions; /* possible codebooks ofr a partition */
int groupbook; /* huffbook for partitioning */
- double partlevels[64]; /* book entropy settings for *encode* */
- int partinterl[64]; /* book subgroup/interleave size for *encode* */
+
+ double ampmax[64]; /* book amp threshholds for *encode* */
int secondstages[64]; /* expanded out to pointers in lookup */
+ long addmullist[64]; /* bitflags for add/mul cascading */
int booklist[256]; /* list of second stage books */
} vorbis_info_residue0;
diff --git a/include/vorbis/codebook.h b/include/vorbis/codebook.h
index 4722e30f..ee4b013e 100644
--- a/include/vorbis/codebook.h
+++ b/include/vorbis/codebook.h
@@ -12,7 +12,7 @@
********************************************************************
function: codebook types
- last mod: $Id: codebook.h,v 1.4.4.4 2000/04/13 00:03:22 xiphmont Exp $
+ last mod: $Id: codebook.h,v 1.4.4.5 2000/04/21 16:35:38 xiphmont Exp $
********************************************************************/
@@ -33,18 +33,20 @@
*/
typedef struct static_codebook{
- long dim; /* codebook dimensions (elements per vector) */
- long entries; /* codebook entries */
+ long dim; /* codebook dimensions (elements per vector) */
+ long entries; /* codebook entries */
+ long *lengthlist; /* codeword lengths in bits */
- /* mapping */
- int q_log; /* 0 == linear, 1 == log (dB) mapping */
+ /* mapping ***************************************************************/
+ int maptype; /* 0=none
+ 1=implicitly populated values from map column
+ 2=listed arbitrary values */
- /* The below does a linear, single monotonic sequence mapping.
- The log mapping uses this, but extends it */
- long q_min; /* packed 32 bit float; quant value 0 maps to minval */
- long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */
- int q_quant; /* bits: 0 < quant <= 16 */
- int q_sequencep; /* bitflag */
+ /* The below does a linear, single monotonic sequence mapping. */
+ long q_min; /* packed 32 bit float; quant value 0 maps to minval */
+ long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */
+ int q_quant; /* bits: 0 < quant <= 16 */
+ int q_sequencep; /* bitflag */
/* additional information for log (dB) mapping; the linear mapping
is assumed to actually be values in dB. encodebias is used to
@@ -52,19 +54,19 @@ typedef struct static_codebook{
zeroflag indicates if entry zero is to represent -Inf dB; negflag
indicates if we're to represent negative linear values in a
mirror of the positive mapping. */
- int q_zeroflag;
- int q_negflag;
- /* encode only values that provide log encoding error parameters */
- double q_encodebias; /* encode only */
- long *quantlist; /* list of dim*entries quantized entry values */
+ long *quantlist; /* map == 1: (int)(entries/dim) element column map
+ map == 2: list of dim*entries quantized entry vals
+ */
- long *lengthlist; /* codeword lengths in bits */
-
- struct encode_aux *encode_tree;
+ /* encode helpers ********************************************************/
+ struct encode_aux_nearestmatch *nearest_tree;
+ struct encode_aux_threshmatch *thresh_tree;
} static_codebook;
-typedef struct encode_aux{
+/* this structures an arbitrary trained book to quickly find the
+ nearest cell match */
+typedef struct encode_aux_nearestmatch{
/* pre-calculated partitioning tree */
long *ptr0;
long *ptr1;
@@ -73,7 +75,14 @@ typedef struct encode_aux{
long *q; /* decision points (each is an entry) */
long aux; /* number of tree entries */
long alloc;
-} encode_aux;
+} encode_aux_nearestmatch;
+
+/* assumes a maptype of 1; encode side only, so that's OK */
+typedef struct encode_aux_threshmatch{
+ double *quantthresh;
+ long *quantmap;
+ int quantvals;
+} encode_aux_threshmatch;
typedef struct decode_aux{
long *ptr0;
@@ -87,7 +96,6 @@ typedef struct codebook{
const static_codebook *c;
double *valuelist; /* list of dim*entries actual entry values */
- double *logdist; /* list of dim*entries metric vals for log encode */
long *codelist; /* list of bitstream codewords for each entry */
struct decode_aux *decode_tree;
diff --git a/include/vorbis/codec.h b/include/vorbis/codec.h
index 1bb5d245..ede1859a 100644
--- a/include/vorbis/codec.h
+++ b/include/vorbis/codec.h
@@ -12,7 +12,7 @@
********************************************************************
function: libvorbis codec headers
- last mod: $Id: codec.h,v 1.10.2.3 2000/04/06 15:59:36 xiphmont Exp $
+ last mod: $Id: codec.h,v 1.10.2.4 2000/04/21 16:35:38 xiphmont Exp $
********************************************************************/
@@ -62,12 +62,9 @@ typedef struct vorbis_info_psy{
double curveatt_4000Hz[5];
double curveatt_8000Hz[5];
- double peakatt_250Hz[5];
- double peakatt_500Hz[5];
- double peakatt_1000Hz[5];
- double peakatt_2000Hz[5];
- double peakatt_4000Hz[5];
- double peakatt_8000Hz[5];
+ int peakattp;
+ double peakatt[6][5]; /* 250,500,1000,2000,4000,8000 Hz @
+ 20, 40 60, 80, 100 dB */
double peakpre;
double peakpost;
diff --git a/include/vorbis/modes.h b/include/vorbis/modes.h
index 5e18865d..687a0a61 100644
--- a/include/vorbis/modes.h
+++ b/include/vorbis/modes.h
@@ -12,7 +12,7 @@
********************************************************************
function: predefined encoding modes
- last mod: $Id: modes.h,v 1.9.2.5 2000/04/13 04:53:03 xiphmont Exp $
+ last mod: $Id: modes.h,v 1.9.2.6 2000/04/21 16:35:38 xiphmont Exp $
********************************************************************/
@@ -30,6 +30,7 @@
#include "vorbis/book/resaux0_long.vqh"
#include "vorbis/book/res0_0a.vqh"
+#include "vorbis/book/res0_1a.vqh"
#include "vorbis/book/res0_0b.vqh"
#include "vorbis/book/res0_0c.vqh"
#include "vorbis/book/res0_0d.vqh"
@@ -39,11 +40,11 @@
/* A farily high quality setting mix */
static vorbis_info_psy _psy_set0={
- 3, /* iterations to fit */
+ 1, /* iterations to fit */
1, /* athp */
1, /* decayp */
- 1,16,4.,
+ 1,8,4.,
-130.,
@@ -54,19 +55,20 @@ static vorbis_info_psy _psy_set0={
{-35.,-40.,-60.,-80.,-100.},
{-35.,-40.,-60.,-80.,-100.},
- /*{-99,-99,-99,-99,-99},
- {-99,-99,-99,-99,-99},
- {-99,-99,-99,-99,-99},
- {-99,-99,-99,-99,-99},
- {-99,-99,-99,-99,-99},
- {-99,-99,-99,-99,-99},*/
- {-8.,-12.,-18.,-20.,-24.},
- {-8.,-12.,-18.,-20.,-24.},
- {-8.,-12.,-18.,-20.,-24.},
- {-8.,-12.,-18.,-20.,-24.},
- {-8.,-12.,-18.,-20.,-24.},
- {-8.,-12.,-18.,-20.,-24.},
- -20.,-10.,
+ 1,
+ {{-6.,-8.,-12.,-16.,-18.},
+ {-6.,-8.,-12.,-16.,-18.},
+ {-6.,-8.,-12.,-16.,-18.},
+ {-6.,-8.,-12.,-16.,-20.},
+ {-6.,-8.,-12.,-16.,-20.},
+ {-6.,-8.,-10.,-14.,-18.},},
+ /*{{-99,-99,-99,-99,-99},
+ {-99,-99,-99,-99,-99},
+ {-99,-99,-99,-99,-99},
+ {-99,-99,-99,-99,-99},
+ {-99,-99,-99,-99,-99},
+ {-99,-99,-99,-99,-99}},*/
+ -80.,-40.,
110.,
@@ -75,21 +77,16 @@ static vorbis_info_psy _psy_set0={
/* with GNUisms, this could be short and readable. Oh well */
static vorbis_info_time0 _time_set0={0};
-static vorbis_info_floor0 _floor_set0={20, 44100, 64,
- /* yes, the first number is different than the ATH */
- {31,31,31,17,15,14,13,13,13,13,12,10,8,6,3,1,0,0,2,4,17,24,27,23,31,86,126},
- 12,150, 1, {0} };
-static vorbis_info_floor0 _floor_set1={32, 44100, 256,
- {31,31,31,17,15,14,13,13,13,13,12,10,8,6,3,1,0,0,2,4,17,24,27,23,31,86,126},
- 12,150, 1, {1} };
+static vorbis_info_floor0 _floor_set0={20, 44100, 64, 12,150, 1, {0} };
+static vorbis_info_floor0 _floor_set1={32, 44100, 256, 12,150, 1, {1} };
static vorbis_info_residue0 _residue_set0={0, 128, 16,8,2,
- {34,46,54,42,30,18, 6, 0},
- { 1, 2, 4, 4, 4, 4, 8, 8},
+ {36,768,512,40240,4048,256, 6, 0},
+ { 1, 2, 2, 4, 4, 4, 8, 8},
{1,1,1,1,1,1,1,0},
{4,5,6,7,8,9,10}};
static vorbis_info_residue0 _residue_set1={0,1024, 16,8,3,
- {34,46,54,42,30,18, 6, 0},
- { 1, 2, 4, 4, 4, 4, 8, 8},
+ {36,768,512,40240,4048,256, 6, 0},
+ { 1, 2, 2, 4, 4, 4, 8, 8},
{1,1,1,1,1,1,1,0},
{4,5,6,7,8,9,10}};
static vorbis_info_mapping0 _mapping_set0={1, {0,0}, {0}, {0}, {0}, {0}};
@@ -123,12 +120,12 @@ vorbis_info info_A={
&_huff_book_resaux0_long,
&_vq_book_res0_0a, /* 4 */
- &_vq_book_res0_0b, /* 5 */
- &_vq_book_res0_0c, /* 6 */
- &_vq_book_res0_0d, /* 7 */
- &_vq_book_res0_0e, /* 8 */
- &_vq_book_res0_0f, /* 9 */
- &_vq_book_res0_0g, /* 10 */
+ &_vq_book_res0_1a, /* 5 */
+ &_vq_book_res0_1a, /* 6 */
+ &_vq_book_res0_1a, /* 7 */
+ &_vq_book_res0_1a, /* 8 */
+ &_vq_book_res0_1a, /* 9 */
+ &_vq_book_res0_1a, /* 10 */
},
/* psy */
{&_psy_set0},
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 121ea23e..797c4300 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -1,6 +1,6 @@
# vorbis makefile configured for use with gcc on any platform
-# $Id: Makefile.in,v 1.24.2.1.2.1 2000/04/02 01:21:21 xiphmont Exp $
+# $Id: Makefile.in,v 1.24.2.1.2.2 2000/04/21 16:35:38 xiphmont Exp $
###############################################################################
# #
@@ -58,11 +58,15 @@ selftest:
$(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST bitwise.c\
-o test_bitwise -lm
$(CC) $(DEBUG) $(LDFLAGS) -c bitwise.c
- $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST codebook.c bitwise.o\
- -o test_codebook -lm
+ $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST sharedbook.c\
+ -o test_sharedbook -lm
+ $(CC) $(DEBUG) $(LDFLAGS) -c sharedbook.c
+ $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST codebook.c \
+ sharedbook.o bitwise.o -o test_codebook -lm
@echo
@./test_framing
@./test_bitwise
+ @./test_sharedbook
@./test_codebook
libvorbis.a: $(LFILES)
@@ -73,7 +77,8 @@ vorbisfile.a: $(LFILES)
$(AR) -r vorbisfile.a $^
$(RANLIB) vorbisfile.a
-psytune: mdct.o psy.o lpc.o smallft.o window.o psytune.o
+psytune: mdct.o psy.o lpc.o smallft.o window.o psytune.o floor0.o \
+ bitwise.o lsp.o codebook.o sharedbook.o
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
diff --git a/lib/bookinternal.h b/lib/bookinternal.h
index f41df5fc..1117bf59 100644
--- a/lib/bookinternal.h
+++ b/lib/bookinternal.h
@@ -12,7 +12,7 @@
********************************************************************
function: basic codebook pack/unpack/code/decode operations
- last mod: $Id: bookinternal.h,v 1.6.4.2 2000/04/02 01:21:21 xiphmont Exp $
+ last mod: $Id: bookinternal.h,v 1.6.4.3 2000/04/21 16:35:38 xiphmont Exp $
********************************************************************/
@@ -27,17 +27,11 @@ extern int vorbis_staticbook_unpack(oggpack_buffer *b,static_codebook *c);
extern int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b);
extern int vorbis_book_encodev(codebook *book, double *a, oggpack_buffer *b);
-extern int vorbis_book_encodevE(codebook *book, double *a, oggpack_buffer *b);
-
extern int vorbis_book_encodevs(codebook *book, double *a, oggpack_buffer *b,
- int step);
-extern int vorbis_book_encodevEs(codebook *book, double *a, oggpack_buffer *b,
- int step);
+ int step,int stagetype);
-extern double vorbis_book_vE(codebook *book, double *a);
extern long vorbis_book_decode(codebook *book, oggpack_buffer *b);
-extern long vorbis_book_decodev(codebook *book, double *a, oggpack_buffer *b);
extern long vorbis_book_decodevs(codebook *book, double *a, oggpack_buffer *b,
- int step);
+ int step,int stagetype);
#endif
diff --git a/lib/codebook.c b/lib/codebook.c
index 8ef16846..3fbc0c36 100644
--- a/lib/codebook.c
+++ b/lib/codebook.c
@@ -12,7 +12,7 @@
********************************************************************
function: basic codebook pack/unpack/code/decode operations
- last mod: $Id: codebook.c,v 1.11.4.4 2000/04/06 15:59:36 xiphmont Exp $
+ last mod: $Id: codebook.c,v 1.11.4.5 2000/04/21 16:35:38 xiphmont Exp $
********************************************************************/
@@ -64,60 +64,82 @@ int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *opb){
}
}
_oggpack_write(opb,i-count,_ilog(c->entries-count));
-
+
}else{
/* length random. Again, we don't code the codeword itself, just
the length. This time, though, we have to encode each length */
_oggpack_write(opb,0,1); /* unordered */
+
+ /* algortihmic mapping has use for 'unused entries', which we tag
+ here. The algorithmic mapping happens as usual, but the unused
+ entry has no codeword. */
for(i=0;i<c->entries;i++)
- _oggpack_write(opb,c->lengthlist[i]-1,5);
+ if(c->lengthlist[i]==0)break;
+
+ if(i==c->entries){
+ _oggpack_write(opb,0,1); /* no unused entries */
+ for(i=0;i<c->entries;i++)
+ _oggpack_write(opb,c->lengthlist[i]-1,5);
+ }else{
+ _oggpack_write(opb,1,1); /* we have unused entries; thus we tag */
+ for(i=0;i<c->entries;i++){
+ if(c->lengthlist[i]==0){
+ _oggpack_write(opb,0,1);
+ }else{
+ _oggpack_write(opb,1,1);
+ _oggpack_write(opb,c->lengthlist[i]-1,5);
+ }
+ }
+ }
}
/* is the entry number the desired return value, or do we have a
- mapping? */
- if(c->quantlist){
- /* we have a mapping. bundle it out. */
- _oggpack_write(opb,1,1);
-
+ mapping? If we have a mapping, what type? */
+ _oggpack_write(opb,c->maptype,4);
+ switch(c->maptype){
+ case 0:
+ /* no mapping */
+ break;
+ case 1:case 2:
+ /* implicitly populated value mapping */
+ /* explicitly populated value mapping */
+
+ if(!c->quantlist){
+ /* no quantlist? error */
+ return(-1);
+ }
+
/* values that define the dequantization */
_oggpack_write(opb,c->q_min,32);
_oggpack_write(opb,c->q_delta,32);
_oggpack_write(opb,c->q_quant-1,4);
_oggpack_write(opb,c->q_sequencep,1);
- _oggpack_write(opb,c->q_log,1);
- if(c->q_log){
- _oggpack_write(opb,c->q_zeroflag,1);
- _oggpack_write(opb,c->q_negflag,1);
- }
+
+ {
+ int quantvals;
+ switch(c->maptype){
+ case 1:
+ /* a single column of (c->entries/c->dim) quantized values for
+ building a full value list algorithmically (square lattice) */
+ quantvals=_book_maptype1_quantvals(c);
+ break;
+ case 2:
+ /* every value (c->entries*c->dim total) specified explicitly */
+ quantvals=c->entries*c->dim;
+ break;
+ }
- /* quantized values */
- for(i=0;i<c->entries*c->dim;i++){
- if(c->quantlist[i]==0){
- if(c->q_zeroflag&&c->q_log)
- _oggpack_write(opb,0,1);
- else{
- /* serious failure; this is an invalid codebook */
- return(1);
- }
- }else{
- if(c->q_zeroflag&&c->q_log)
- _oggpack_write(opb,1,1);
+ /* quantized values */
+ for(i=0;i<quantvals;i++)
+ _oggpack_write(opb,labs(c->quantlist[i]),c->q_quant);
- _oggpack_write(opb,labs(c->quantlist[i])-1,c->q_quant);
- if(c->q_negflag&&c->q_log){
- if(c->quantlist[i]>0){
- _oggpack_write(opb,0,1);
- }else{
- _oggpack_write(opb,1,1);
- }
- }
- }
}
- }else{
- /* no mapping. */
- _oggpack_write(opb,0,1);
+ break;
+ default:
+ /* error case; we don't have any other map types now */
+ return(-1);
}
-
+
return(0);
}
@@ -140,10 +162,26 @@ int vorbis_staticbook_unpack(oggpack_buffer *opb,static_codebook *s){
case 0:
/* unordered */
s->lengthlist=malloc(sizeof(long)*s->entries);
- for(i=0;i<s->entries;i++){
- long num=_oggpack_read(opb,5);
- if(num==-1)goto _eofout;
- s->lengthlist[i]=num+1;
+
+ /* allocated but unused entries? */
+ if(_oggpack_read(opb,1)){
+ /* yes, unused entries */
+
+ for(i=0;i<s->entries;i++){
+ if(_oggpack_read(opb,1)){
+ long num=_oggpack_read(opb,5);
+ if(num==-1)goto _eofout;
+ s->lengthlist[i]=num+1;
+ }else
+ s->lengthlist[i]=0;
+ }
+ }else{
+ /* all entries used; no tagging */
+ for(i=0;i<s->entries;i++){
+ long num=_oggpack_read(opb,5);
+ if(num==-1)goto _eofout;
+ s->lengthlist[i]=num+1;
+ }
}
break;
@@ -152,7 +190,7 @@ int vorbis_staticbook_unpack(oggpack_buffer *opb,static_codebook *s){
{
long length=_oggpack_read(opb,5)+1;
s->lengthlist=malloc(sizeof(long)*s->entries);
-
+
for(i=0;i<s->entries;){
long num=_oggpack_read(opb,_ilog(s->entries-i));
if(num==-1)goto _eofout;
@@ -168,99 +206,102 @@ int vorbis_staticbook_unpack(oggpack_buffer *opb,static_codebook *s){
}
/* Do we have a mapping to unpack? */
- if(_oggpack_read(opb,1)){
+ switch((s->maptype=_oggpack_read(opb,4))){
+ case 0:
+ /* no mapping */
+ break;
+ case 1: case 2:
+ /* implicitly populated value mapping */
+ /* explicitly populated value mapping */
- /* values that define the dequantization */
s->q_min=_oggpack_read(opb,32);
s->q_delta=_oggpack_read(opb,32);
s->q_quant=_oggpack_read(opb,4)+1;
s->q_sequencep=_oggpack_read(opb,1);
- s->q_log=_oggpack_read(opb,1);
- if(s->q_log){
- s->q_zeroflag=_oggpack_read(opb,1);
- s->q_negflag=_oggpack_read(opb,1);
- }else{
- /* zero/negflag must be zero if log is */
- s->q_zeroflag=0;
- s->q_negflag=0;
- }
-
- /* quantized values */
- s->quantlist=malloc(sizeof(double)*s->entries*s->dim);
- for(i=0;i<s->entries*s->dim;i++){
- if(s->q_zeroflag)
- if(_oggpack_read(opb,1)==0){
- s->quantlist[i]=0;
- continue;
- }
- s->quantlist[i]=_oggpack_read(opb,s->q_quant);
- if(s->quantlist[i]==-1)goto _eofout;
- s->quantlist[i]++;
-
- /* if we're log scale, a negative dB value is a positive linear
- value (just < 1.) We need an additional bit to set
- positive/negative linear side. */
- if(s->q_negflag)
- if(_oggpack_read(opb,1))
- s->quantlist[i]= -s->quantlist[i];
+ {
+ int quantvals;
+ switch(s->maptype){
+ case 1:
+ quantvals=_book_maptype1_quantvals(s);
+ break;
+ case 2:
+ quantvals=s->entries*s->dim;
+ break;
+ }
+
+ /* quantized values */
+ s->quantlist=malloc(sizeof(double)*quantvals);
+ for(i=0;i<quantvals;i++)
+ s->quantlist[i]=_oggpack_read(opb,s->q_quant);
+
+ if(s->quantlist[quantvals-1]==-1)goto _eofout;
}
+ break;
+ default:
+ goto _errout;
}
/* all set */
return(0);
-
+
_errout:
_eofout:
vorbis_staticbook_clear(s);
return(-1);
}
-/* returns the number of bits ***************************************/
+/* returns the number of bits ************************************************/
int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){
_oggpack_write(b,book->codelist[a],book->c->lengthlist[a]);
return(book->c->lengthlist[a]);
}
+/* One the encode side, our vector writers are each designed for a
+specific purpose, and the encoder is not flexible without modification:
+
+The LSP vector coder uses a single stage nearest-match with no
+interleave, so no step and no error return. This is specced by floor0
+and doesn't change.
+
+Residue0 encoding interleaves, uses multiple stages, and each stage
+peels of a specific amount of resolution from a lattice (thus we want
+to match by threshhold, not nearest match). Residue doesn't *have* to
+be encoded that way, but to change it, one will need to add more
+infrastructure on the encode side (decode side is specced and simpler) */
+
+/* floor0 LSP (single stage, non interleaved, nearest match) */
/* returns the number of bits and *modifies a* to the quantization value *****/
-int vorbis_book_encodevs(codebook *book,double *a,oggpack_buffer *b,int step){
- int dim=book->dim,k,o;
- int best=(book->c->q_log?_logbest(book,a,step):_best(book,a,step));
- for(k=0,o=0;k<dim;k++,o+=step)
- a[o]=(book->valuelist+best*dim)[k];
+int vorbis_book_encodev(codebook *book,double *a,oggpack_buffer *b){
+ int dim=book->dim,k;
+ int best=_best(book,a,1);
+ for(k=0;k<dim;k++)
+ a[k]=(book->valuelist+best*dim)[k];
return(vorbis_book_encode(book,best,b));
}
-int vorbis_book_encodev(codebook *book, double *a, oggpack_buffer *b){
- return vorbis_book_encodevs(book,a,b,1);
-}
+/* res0 (multistage, interleave, lattice) */
+/* returns the number of bits and *modifies a* to the remainder value ********/
+int vorbis_book_encodevs(codebook *book,double *a,oggpack_buffer *b,
+ int step,int addmul){
-/* returns the number of bits and *modifies a* to the quantization error *****/
-int vorbis_book_encodevEs(codebook *book,double *a,oggpack_buffer *b,int step){
- int dim=book->dim,k,o;
- int best=(book->c->q_log?_logbest(book,a,step):_best(book,a,step));
- for(k=0,o=0;k<dim;k++,o+=step)
- a[o]-=(book->valuelist+best*dim)[k];
+ int best=vorbis_book_besterror(book,a,step,addmul);
return(vorbis_book_encode(book,best,b));
}
-int vorbis_book_encodevE(codebook *book,double *a,oggpack_buffer *b){
- return vorbis_book_encodevEs(book,a,b,1);
-}
+/* Decode side is specced and easier, because we don't need to find
+ matches using different criteria; we simply read and map. There are
+ two things we need to do 'depending':
+
+ We may need to support interleave. We don't really, but it's
+ convenient to do it here rather than rebuild the vector later.
-/* returns the total squared quantization error for best match and sets each
- element of a to local error ***************/
-double vorbis_book_vE(codebook *book, double *a){
- int dim=book->dim,k;
- int best=(book->c->q_log?_logbest(book,a,1):_best(book,a,1));
- double acc=0.;
- for(k=0;k<dim;k++){
- double val=(book->valuelist+best*dim)[k];
- a[k]-=val;
- acc+=a[k]*a[k];
- }
- return(acc);
-}
+ Cascades may be additive or multiplicitive; this is not inherent in
+ the codebook, but set in the code using the codebook. Like
+ interleaving, it's easiest to do it here.
+ stage==0 -> declarative (set the value)
+ stage==1 -> additive
+ stage==2 -> multiplicitive */
/* returns the entry number or -1 on eof *************************************/
long vorbis_book_decode(codebook *book, oggpack_buffer *b){
@@ -282,20 +323,28 @@ long vorbis_book_decode(codebook *book, oggpack_buffer *b){
}
/* returns the entry number or -1 on eof *************************************/
-long vorbis_book_decodevs(codebook *book,double *a,oggpack_buffer *b,int step){
+long vorbis_book_decodevs(codebook *book,double *a,oggpack_buffer *b,
+ int step,int addmul){
long entry=vorbis_book_decode(book,b);
int i,o;
if(entry==-1)return(-1);
- for(i=0,o=0;i<book->dim;i++,o+=step)
- a[o]+=(book->valuelist+entry*book->dim)[i];
+ switch(addmul){
+ case -1:
+ for(i=0,o=0;i<book->dim;i++,o+=step)
+ a[o]=(book->valuelist+entry*book->dim)[i];
+ break;
+ case 0:
+ for(i=0,o=0;i<book->dim;i++,o+=step)
+ a[o]+=(book->valuelist+entry*book->dim)[i];
+ break;
+ case 1:
+ for(i=0,o=0;i<book->dim;i++,o+=step)
+ a[o]*=(book->valuelist+entry*book->dim)[i];
+ break;
+ }
return(entry);
}
-long vorbis_book_decodev(codebook *book, double *a, oggpack_buffer *b){
- return vorbis_book_decodevs(book,a,b,1);
-}
-
-
#ifdef _V_SELFTEST
/* Simple enough; pack a few candidate codebooks, unpack them. Code a
@@ -306,10 +355,10 @@ long vorbis_book_decodev(codebook *book, double *a, oggpack_buffer *b){
#include <stdio.h>
#include "vorbis/book/lsp20_0.vqh"
#include "vorbis/book/lsp32_0.vqh"
+#include "vorbis/book/res0_1a.vqh"
#define TESTSIZE 40
-#define TESTDIM 4
-double test1[40]={
+double test1[TESTSIZE]={
0.105939,
0.215373,
0.429117,
@@ -361,7 +410,7 @@ double test1[40]={
0.708603,
};
-double test2[40]={
+double test2[TESTSIZE]={
0.088654,
0.165742,
0.279013,
@@ -413,8 +462,16 @@ double test2[40]={
0.375124,
};
-static_codebook *testlist[]={&_vq_book_lsp20_0,&_vq_book_lsp32_0,NULL};
-double *testvec[]={test1,test2};
+double test3[TESTSIZE]={
+ 0,1,-2,3,4,-5,6,7,8,9,
+ 8,-2,7,-1,4,6,8,3,1,-9,
+ 10,11,12,13,14,15,26,17,18,19,
+ 30,-25,-30,-1,-5,-32,4,3,-2,0};
+
+static_codebook *testlist[]={&_vq_book_lsp20_0,
+ &_vq_book_lsp32_0,
+ &_vq_book_res0_1a,NULL};
+double *testvec[]={test1,test2,test3};
int main(){
oggpack_buffer write;
@@ -440,10 +497,10 @@ int main(){
we can write */
vorbis_staticbook_pack(testlist[ptr],&write);
fprintf(stderr,"Codebook size %ld bytes... ",_oggpack_bytes(&write));
- for(i=0;i<TESTSIZE;i+=TESTDIM)
+ for(i=0;i<TESTSIZE;i+=c.dim)
vorbis_book_encodev(&c,qv+i,&write);
vorbis_book_clear(&c);
-
+
fprintf(stderr,"OK.\n");
fprintf(stderr,"\tunpacking/decoding %ld... ",ptr);
@@ -458,15 +515,15 @@ int main(){
exit(1);
}
- for(i=0;i<TESTSIZE;i+=TESTDIM)
- if(vorbis_book_decodev(&c,iv+i,&read)==-1){
+ for(i=0;i<TESTSIZE;i+=c.dim)
+ if(vorbis_book_decodevs(&c,iv+i,&read,1,-1)==-1){
fprintf(stderr,"Error reading codebook test data (EOP).\n");
exit(1);
}
for(i=0;i<TESTSIZE;i++)
if(fabs(qv[i]-iv[i])>.000001){
- fprintf(stderr,"input (%g) != output (%g) at position (%ld)\n",
- iv[i],testvec[ptr][i]-qv[i],i);
+ fprintf(stderr,"read (%g) != written (%g) at position (%ld)\n",
+ iv[i],qv[i],i);
exit(1);
}
diff --git a/lib/floor0.c b/lib/floor0.c
index 3c697567..ea20c6a5 100644
--- a/lib/floor0.c
+++ b/lib/floor0.c
@@ -12,7 +12,7 @@
********************************************************************
function: floor backend 0 implementation
- last mod: $Id: floor0.c,v 1.11.2.1.2.4 2000/04/13 04:53:04 xiphmont Exp $
+ last mod: $Id: floor0.c,v 1.11.2.1.2.5 2000/04/21 16:35:38 xiphmont Exp $
********************************************************************/
@@ -33,7 +33,6 @@ typedef struct {
int ln;
int m;
int *linearmap;
- double *subcurve;
vorbis_info_floor0 *vi;
lpc_lookup lpclook;
@@ -50,7 +49,6 @@ static void free_look(vorbis_look_floor *i){
vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
if(i){
if(look->linearmap)free(look->linearmap);
- if(look->subcurve)free(look->subcurve);
lpc_clear(&look->lpclook);
memset(look,0,sizeof(vorbis_look_floor0));
free(look);
@@ -65,8 +63,6 @@ static void pack (vorbis_info_floor *i,oggpack_buffer *opb){
_oggpack_write(opb,info->barkmap,16);
_oggpack_write(opb,info->ampbits,6);
_oggpack_write(opb,info->ampdB,8);
- for(j=0;j<27;j++)
- _oggpack_write(opb,(int)info->subcurve[j],8);
_oggpack_write(opb,info->numbooks-1,4);
for(j=0;j<info->numbooks;j++)
_oggpack_write(opb,info->books[j],8);
@@ -80,8 +76,6 @@ static vorbis_info_floor *unpack (vorbis_info *vi,oggpack_buffer *opb){
info->barkmap=_oggpack_read(opb,16);
info->ampbits=_oggpack_read(opb,6);
info->ampdB=_oggpack_read(opb,8);
- for(j=0;j<27;j++)
- info->subcurve[j]=_oggpack_read(opb,8);
info->numbooks=_oggpack_read(opb,4)+1;
if(info->order<1)goto err_out;
@@ -138,23 +132,6 @@ static vorbis_look_floor *look (vorbis_dsp_state *vd,vorbis_info_mode *mi,
if(val>look->ln)val=look->ln; /* guard against the approximation */
look->linearmap[j]=val;
}
- look->subcurve=malloc(look->ln*sizeof(double));
- {
- double max=toBARK(info->rate/2.);
- for(j=0;j<look->ln;j++){
- double bark=max/look->ln*j;
- int f=floor(bark);
- double del=bark-f;
-
- if(f>=27){
- f=26;
- del=1.;
- }
-
- look->subcurve[j]=info->subcurve[f]*(1.-del)+info->subcurve[f+1]*del;
- }
- }
-
return look;
}
@@ -163,7 +140,7 @@ static vorbis_look_floor *look (vorbis_dsp_state *vd,vorbis_info_mode *mi,
/* less efficient than the decode side (written for clarity). We're
not bottlenecked here anyway */
-static double _curve_to_lpc(double *curve,double *lpc,vorbis_look_floor0 *l,
+double _curve_to_lpc(double *curve,double *lpc,vorbis_look_floor0 *l,
long frameno){
/* map the input curve to a bark-scale curve for encoding */
@@ -201,7 +178,6 @@ static double _curve_to_lpc(double *curve,double *lpc,vorbis_look_floor0 *l,
}
last=bark;
}
- for(i=0;i<l->ln;i++)work[i]-=l->subcurve[i];
#if 0
{ /******************/
@@ -222,7 +198,7 @@ static double _curve_to_lpc(double *curve,double *lpc,vorbis_look_floor0 *l,
/* generate the whole freq response curve of an LPC IIR filter */
-static void _lpc_to_curve(double *curve,double *lpc,double amp,
+void _lpc_to_curve(double *curve,double *lpc,double amp,
vorbis_look_floor0 *l,char *name,long frameno){
double *lcurve=alloca(sizeof(double)*(l->ln*2));
int i;
@@ -247,7 +223,6 @@ static void _lpc_to_curve(double *curve,double *lpc,double amp,
}
#endif
- for(i=0;i<l->ln;i++)lcurve[i]+=l->subcurve[i];
for(i=0;i<l->n;i++)curve[i]=lcurve[l->linearmap[i]];
}
@@ -257,16 +232,17 @@ static int forward(vorbis_block *vb,vorbis_look_floor *i,
long j,k;
vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
vorbis_info_floor0 *info=look->vi;
+ double *work=alloca(look->n*sizeof(double));
double amp;
long bits=0;
/* our floor comes in on a linear scale; go to a [-Inf...0] dB
scale. The curve has to be positive, so we offset it. */
- for(j=0;j<look->n;j++)in[j]=todB(in[j])+info->ampdB;
-
+ for(j=0;j<look->n;j++)work[j]=todB(in[j])+info->ampdB;
+
/* use 'out' as temp storage */
/* Convert our floor to a set of lpc coefficients */
- amp=sqrt(_curve_to_lpc(in,out,look,vb->sequence));
+ amp=sqrt(_curve_to_lpc(work,out,look,vb->sequence));
/* amp is in the range (0. to ampdB]. Encode that range using
ampbits bits */
@@ -274,14 +250,14 @@ static int forward(vorbis_block *vb,vorbis_look_floor *i,
{
long maxval=(1<<info->ampbits)-1;
- long val=amp/info->ampdB*maxval+1;
+ long val=rint(amp/info->ampdB*maxval);
if(val<0)val=0; /* likely */
if(val>maxval)val=maxval; /* not bloody likely */
_oggpack_write(&vb->opb,val,info->ampbits);
if(val>0)
- amp=(val-.5)/maxval*info->ampdB;
+ amp=(float)val/maxval*info->ampdB;
else
amp=0;
}
@@ -307,8 +283,8 @@ static int forward(vorbis_block *vb,vorbis_look_floor *i,
#if 0
{ /******************/
- vorbis_lsp_to_lpc(out,in,look->m);
- _lpc_to_curve(in,in,amp,look,"Fprefloor",vb->sequence);
+ vorbis_lsp_to_lpc(out,work,look->m);
+ _lpc_to_curve(work,work,amp,look,"Fprefloor",vb->sequence);
}
#endif
@@ -347,10 +323,10 @@ static int inverse(vorbis_block *vb,vorbis_look_floor *i,double *out){
vorbis_info_floor0 *info=look->vi;
int j,k;
- long ampraw=_oggpack_read(&vb->opb,info->ampbits);
+ int ampraw=_oggpack_read(&vb->opb,info->ampbits);
if(ampraw>0){
long maxval=(1<<info->ampbits)-1;
- double amp=(ampraw-.5)/maxval*info->ampdB;
+ double amp=(float)ampraw/maxval*info->ampdB;
int booknum=_oggpack_read(&vb->opb,_ilog(info->numbooks));
codebook *b=vb->vd->fullbooks+info->books[booknum];
double last=0.;
@@ -358,7 +334,7 @@ static int inverse(vorbis_block *vb,vorbis_look_floor *i,double *out){
memset(out,0,sizeof(double)*look->m);
for(j=0;j<look->m;j+=b->dim)
- vorbis_book_decodev(b,out+j,&vb->opb);
+ vorbis_book_decodevs(b,out+j,&vb->opb,1,-1);
for(j=0;j<look->m;){
for(k=0;k<b->dim;k++,j++)out[j]+=last;
last=out[j-1];
diff --git a/lib/framing.c b/lib/framing.c
index 3fb06477..3858235b 100644
--- a/lib/framing.c
+++ b/lib/framing.c
@@ -13,7 +13,7 @@
function: code raw [Vorbis] packets into framed OggSquish stream and
decode Ogg streams back into raw packets
- last mod: $Id: framing.c,v 1.14.4.1 2000/04/06 15:59:36 xiphmont Exp $
+ last mod: $Id: framing.c,v 1.14.4.2 2000/04/21 16:35:39 xiphmont Exp $
note: The CRC code is directly derived from public domain code by
Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include <string.h>
#include "vorbis/codec.h"
+#include "misc.h"
/* A complete description of Ogg framing exists in docs/framing.html */
@@ -302,6 +303,11 @@ int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
/* 32 bits of page counter (we have both counter and page header
because this val can roll over) */
+ if(os->pageno==-1)os->pageno=0; /* because someone called
+ stream_reset; this would be a
+ strange thing to do in an
+ encode stream, but it has
+ plausible uses */
{
long pageno=os->pageno++;
for(i=18;i<22;i++){
@@ -874,8 +880,8 @@ void test_pack(int *pl, int **headers){
int eosflag=0;
int bosflag=0;
- ogg_stream_reset(&os_en,0);
- ogg_stream_reset(&os_de,0);
+ ogg_stream_reset(&os_en);
+ ogg_stream_reset(&os_de);
ogg_sync_reset(&oy);
for(packets=0;;packets++)if(pl[packets]==-1)break;
@@ -1302,7 +1308,7 @@ int main(void){
int inptr=0,i,j;
ogg_page og[5];
- ogg_stream_reset(&os_en,0);
+ ogg_stream_reset(&os_en);
for(i=0;pl[i]!=-1;i++){
ogg_packet op;
@@ -1336,7 +1342,7 @@ int main(void){
fprintf(stderr,"Testing loss of pages... ");
ogg_sync_reset(&oy);
- ogg_stream_reset(&os_de,0);
+ ogg_stream_reset(&os_de);
for(i=0;i<5;i++){
memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
og[i].header_len);
@@ -1381,7 +1387,7 @@ int main(void){
fprintf(stderr,"Testing loss of pages (rollback required)... ");
ogg_sync_reset(&oy);
- ogg_stream_reset(&os_de,0);
+ ogg_stream_reset(&os_de);
for(i=0;i<5;i++){
memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
og[i].header_len);
diff --git a/lib/info.c b/lib/info.c
index a7b22c7f..90fb4158 100644
--- a/lib/info.c
+++ b/lib/info.c
@@ -12,7 +12,7 @@
********************************************************************
function: maintain the info structure, info <-> header packets
- last mod: $Id: info.c,v 1.22.4.1 2000/04/04 07:08:44 xiphmont Exp $
+ last mod: $Id: info.c,v 1.22.4.2 2000/04/21 16:35:39 xiphmont Exp $
********************************************************************/
@@ -341,7 +341,7 @@ static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){
}
static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){
- char temp[]="Xiphophorus libVorbis I 20000223";
+ char temp[]="Xiphophorus libVorbis I 20000415";
/* preamble */
_oggpack_write(opb,0x03,8);
diff --git a/lib/lsp.c b/lib/lsp.c
index ba42a23d..9ea4d244 100644
--- a/lib/lsp.c
+++ b/lib/lsp.c
@@ -12,7 +12,7 @@
********************************************************************
function: LSP (also called LSF) conversion routines
- last mod: $Id: lsp.c,v 1.4.4.2 2000/04/06 16:47:45 xiphmont Exp $
+ last mod: $Id: lsp.c,v 1.4.4.3 2000/04/21 16:35:39 xiphmont Exp $
The LSP generation code is taken (with minimal modification) from
"On the Computation of the LSP Frequencies" by Joseph Rothweiler
@@ -22,6 +22,16 @@
********************************************************************/
+/* Note that the lpc-lsp conversion finds the roots of polynomial with
+ an iterative root polisher (CACM algorithm 283). It *is* possible
+ to confuse this algorithm into not converging; that should only
+ happen with absurdly closely spaced roots (very sharp peaks in the
+ LPC f response) which in turn should be impossible in our use of
+ the code. If this *does* happen anyway, it's a bug in the floor
+ finder; find the cause of the confusion (probably a single bin
+ spike or accidental near-double-limit resolution problems) and
+ correct it. */
+
#include <math.h>
#include <string.h>
#include <stdlib.h>
@@ -76,29 +86,18 @@ void vorbis_lsp_to_lpc(double *lsp,double *lpc,int m){
}
}
-static void kw(double *r,int n) {
- double *s=alloca(sizeof(double)*(n/2+1));
- double *c=alloca(sizeof(double)*(n+1));
- int i, j, k;
-
- s[0] = 1.0;
- s[1] = -2.0;
- s[2] = 2.0;
- for(i=3;i<=n/2;i++) s[i] = s[i-2];
-
- for(k=0;k<=n;k++) {
- c[k] = r[k];
- j = 1;
- for(i=k+2;i<=n;i+=2) {
- c[k] += s[j]*r[i];
- s[j] -= s[j-1];
- j++;
+static void cheby(double *g, int ord) {
+ int i, j;
+
+ g[0] *= 0.5;
+ for(i=2; i<= ord; i++) {
+ for(j=ord; j >= i; j--) {
+ g[j-2] -= g[j];
+ g[j] += g[j];
}
}
- for(k=0;k<=n;k++) r[k] = c[k];
}
-
static int comp(const void *a,const void *b){
if(*(double *)a<*(double *)b)
return(1);
@@ -126,6 +125,7 @@ static void cacm283(double *a,int ord,double *r){
}
delta = val/p;
r[i] -= delta;
+
error += delta*delta;
}
}
@@ -160,8 +160,8 @@ void vorbis_lpc_to_lsp(double *lpc,double *lsp,int m){
for(i=0; i<order2;i++) g2[order2-i-1] += g2[order2-i];
/* Convert into polynomials in cos(alpha) */
- kw(g1,order2);
- kw(g2,order2);
+ cheby(g1,order2);
+ cheby(g2,order2);
/* Find the roots of the 2 even polynomials.*/
@@ -169,7 +169,7 @@ void vorbis_lpc_to_lsp(double *lpc,double *lsp,int m){
cacm283(g2,order2,g2r);
for(i=0;i<m;i+=2){
- lsp[i] = acos(g1r[i/2]*.5);
- lsp[i+1] = acos(g2r[i/2]*.5);
+ lsp[i] = acos(g1r[i/2]);
+ lsp[i+1] = acos(g2r[i/2]);
}
}
diff --git a/lib/mapping0.c b/lib/mapping0.c
index a1a88259..381ed62b 100644
--- a/lib/mapping0.c
+++ b/lib/mapping0.c
@@ -12,7 +12,7 @@
********************************************************************
function: channel mapping 0 implementation
- last mod: $Id: mapping0.c,v 1.11.2.2.2.4 2000/04/13 04:53:04 xiphmont Exp $
+ last mod: $Id: mapping0.c,v 1.11.2.2.2.5 2000/04/21 16:35:39 xiphmont Exp $
********************************************************************/
@@ -245,21 +245,21 @@ static int forward(vorbis_block *vb,vorbis_look_mapping *l){
memset(decay,0,n*sizeof(double)/2);
/* perform psychoacoustics; do masking */
- _vp_tone_tone_mask(look->psy_look+submap,pcm,mask,decay);
+ _vp_tone_tone_mask(look->psy_look+submap,pcm,floor,mask,decay);
_analysis_output("mdct",vb->sequence,pcm,n/2,0,1);
_analysis_output("mask",vb->sequence,mask,n/2,0,1);
/* perform floor encoding */
nonzero[i]=look->floor_func[submap]->
- forward(vb,look->floor_look[submap],mask,floor);
+ forward(vb,look->floor_look[submap],floor,floor);
_analysis_output("floor",vb->sequence,floor,n/2,0,1);
/* apply the floor, do optional noise levelling */
- _vp_apply_floor(look->psy_look+submap,pcm,floor);
+ _vp_apply_floor(look->psy_look+submap,pcm,floor,mask);
- _analysis_output("res",vb->sequence,pcm,n/2,0,1);
+ _analysis_output("res",vb->sequence,pcm,n/2,0,0);
#ifdef TRAIN
if(nonzero[i]){
@@ -342,7 +342,7 @@ static int inverse(vorbis_block *vb,vorbis_look_mapping *l){
/* only MDCT right now.... */
for(i=0;i<vi->channels;i++){
double *pcm=vb->pcm[i];
- _analysis_output("out",vb->sequence,pcm,n/2,0,1);
+ _analysis_output("out",vb->sequence,pcm,n/2,0,0);
mdct_backward(vd->transform[vb->W][0],pcm,pcm);
}
diff --git a/lib/psy.c b/lib/psy.c
index 7f9ab852..4421259d 100644
--- a/lib/psy.c
+++ b/lib/psy.c
@@ -12,7 +12,7 @@
********************************************************************
function: psychoacoustics not including preecho
- last mod: $Id: psy.c,v 1.16.2.2.2.8 2000/04/12 08:47:53 xiphmont Exp $
+ last mod: $Id: psy.c,v 1.16.2.2.2.9 2000/04/21 16:35:39 xiphmont Exp $
********************************************************************/
@@ -94,7 +94,6 @@ static void interp_curve(double *c,double *c1,double *c2,double del){
static void setup_curve(double **c,
int oc,
double *curveatt_dB,
- double *peakatt_dB,
double peaklowrolloff,
double peakhighrolloff){
int i,j;
@@ -127,22 +126,6 @@ static void setup_curve(double **c,
attenuate_curve(tempc[i*2],curveatt_dB[i]);
}
- /* add in the additional peak attenuation hack */
- for(i=0;i<5;i++){
- double att=peakatt_dB[i];
- for(j=EHMER_OFFSET;j<EHMER_MAX && att>tempc[i*2][j];j++){
- c[i*2][j]=att;
- tempc[i*2][j]=att;
- att+=peakhighrolloff;
- }
- att=peakatt_dB[i]+peaklowrolloff;
- for(j=EHMER_OFFSET-1;j>=0 && att>tempc[i*2][j];j--){
- c[i*2][j]=att;
- tempc[i*2][j]=att;
- att+=peaklowrolloff;
- }
- }
-
/* The c array is comes in as dB curves at 20 40 60 80 100 dB.
interpolate intermediate dB curves */
for(i=0;i<7;i+=2){
@@ -238,18 +221,12 @@ void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi,int n,long rate){
memcpy(p->curves[10][6],tone_4000_80dB_SL,sizeof(double)*EHMER_MAX);
memcpy(p->curves[10][8],tone_8000_100dB_SL,sizeof(double)*EHMER_MAX);
- setup_curve(p->curves[0],0,vi->curveatt_250Hz,vi->peakatt_250Hz,
- vi->peakpre,vi->peakpost);
- setup_curve(p->curves[2],2,vi->curveatt_500Hz,vi->peakatt_500Hz,
- vi->peakpre,vi->peakpost);
- setup_curve(p->curves[4],4,vi->curveatt_1000Hz,vi->peakatt_1000Hz,
- vi->peakpre,vi->peakpost);
- setup_curve(p->curves[6],6,vi->curveatt_2000Hz,vi->peakatt_2000Hz,
- vi->peakpre,vi->peakpost);
- setup_curve(p->curves[8],8,vi->curveatt_4000Hz,vi->peakatt_4000Hz,
- vi->peakpre,vi->peakpost);
- setup_curve(p->curves[10],10,vi->curveatt_8000Hz,vi->peakatt_8000Hz,
- vi->peakpre,vi->peakpost);
+ setup_curve(p->curves[0],0,vi->curveatt_250Hz,vi->peakpre,vi->peakpost);
+ setup_curve(p->curves[2],2,vi->curveatt_500Hz,vi->peakpre,vi->peakpost);
+ setup_curve(p->curves[4],4,vi->curveatt_1000Hz,vi->peakpre,vi->peakpost);
+ setup_curve(p->curves[6],6,vi->curveatt_2000Hz,vi->peakpre,vi->peakpost);
+ setup_curve(p->curves[8],8,vi->curveatt_4000Hz,vi->peakpre,vi->peakpost);
+ setup_curve(p->curves[10],10,vi->curveatt_8000Hz,vi->peakpre,vi->peakpost);
for(i=1;i<11;i+=2)
for(j=0;j<9;j++)
@@ -357,8 +334,10 @@ static void add_seeds(double *floor,int n){
/* Why Bark scale for encoding but not masking? Because masking has a
strong harmonic dependancy */
-static void _vp_tone_tone_iter(vorbis_look_psy *p,double *f, double *flr,
- double *decay){
+static void _vp_tone_tone_iter(vorbis_look_psy *p,
+ double *f,
+ double *flr, double *mask,
+ double *decay){
vorbis_info_psy *vi=p->vi;
long n=p->n,i;
double *work=alloca(n*sizeof(double));
@@ -393,7 +372,7 @@ static void _vp_tone_tone_iter(vorbis_look_psy *p,double *f, double *flr,
/* prime the working vector with peak values */
/* Use the 250 Hz curve up to 250 Hz and 8kHz curve after 8kHz. */
for(i=0;i<n;i++){
- acc+=flr[i];
+ acc+=flr[i]; /* XXX acc is behaving incorrectly. Check it */
if(work[i]*work[i]>acc){
int o=rint(p->octave[i]*2.);
if(o<0)o=0;
@@ -404,30 +383,78 @@ static void _vp_tone_tone_iter(vorbis_look_psy *p,double *f, double *flr,
}
}
- /* now, chase curves down from the peak seeds */
+ /* chase curves down from the peak seeds */
add_seeds(flr,n);
+
+ memcpy(mask,flr,n*sizeof(double));
/* mask off the ATH */
- if(p->vi->athp)
+ if(vi->athp)
for(i=0;i<n;i++)
- if(flr[i]<p->ath[i])
- flr[i]=p->ath[i];
+ if(mask[i]<p->ath[i])
+ mask[i]=p->ath[i];
+ /* do the peak att with rolloff hack. But I don't know which is
+ better... doing it to mask or floor. We'll assume mask right now */
+ if(vi->peakattp){
+ double curmask;
+
+ /* seed peaks for rolloff first so we only do it once */
+ for(i=0;i<n;i++){
+ if(work[i]>mask[i]){
+ double val=todB(work[i]);
+ int o=p->octave[i];
+ int choice=rint((val-specmax+vi->max_curve_dB)/20.)-1;
+ if(o<0)o=0;
+ if(o>5)o=5;
+ if(choice<0)choice=0;
+ if(choice>4)choice=4;
+ work[i]=fromdB(val+vi->peakatt[o][choice]);
+ }else{
+ work[i]=0;
+ }
+ }
+
+ /* chase down from peaks forward */
+ curmask=0.;
+ for(i=0;i<n-1;i++){
+ if(work[i]>curmask)curmask=work[i];
+ if(curmask>mask[i]){
+ mask[i]=curmask;
+ /* roll off the curmask */
+ curmask*=fromdB(vi->peakpost*(p->octave[i+1]-p->octave[i]));
+ }else{
+ curmask=0;
+ }
+ }
+ /* chase down from peaks backward */
+ curmask=0.;
+ for(i=n-1;i>0;i--){
+ if(work[i]>curmask)curmask=work[i];
+ if(curmask>=mask[i]){
+ mask[i]=curmask;
+ /* roll off the curmask */
+ curmask*=fromdB(vi->peakpre*(p->octave[i]-p->octave[i-1]));
+ }else{
+ curmask=0;
+ }
+ }
+ }
}
/* stability doesn't matter */
static int comp(const void *a,const void *b){
if(fabs(**(double **)a)<fabs(**(double **)b))
- return(-1);
- else
return(1);
+ else
+ return(-1);
}
/* this applies the floor and (optionally) tries to preserve noise
energy in low resolution portions of the spectrum */
/* f and flr are *linear* scale, not dB */
void _vp_apply_floor(vorbis_look_psy *p,double *f,
- double *flr){
+ double *flr,double *mask){
double *work=alloca(p->n*sizeof(double));
double thresh=fromdB(p->vi->noisefit_threshdB);
int i,j,addcount=0;
@@ -438,9 +465,12 @@ void _vp_apply_floor(vorbis_look_psy *p,double *f,
if(flr[j]<=0)
work[j]=0.;
else{
- double val=f[j]/flr[j];
- if(fabs(val)<1.)val=0.;
- work[j]=val;
+ if(fabs(f[j])<mask[j] || fabs(f[j])<flr[j]){
+ work[j]=0;
+ }else{
+ double val=f[j]/flr[j];
+ work[j]=val;
+ }
}
}
@@ -471,22 +501,26 @@ void _vp_apply_floor(vorbis_look_psy *p,double *f,
}
}
- /* sort the zeroed values; add back the largest first, stop when
- we violate the desired result above (which may be
+ /* sort the values below mask; add back the largest first, stop
+ when we violate the desired result above (which may be
immediately) */
if(z && current_SL*thresh<original_SL){
qsort(index,z,sizeof(double *),&comp);
for(j=0;j<z;j++){
int p=index[j]-f;
- double val=flr[p]*flr[p]+current_SL;
+
+ /* yes, I mean *mask* here, not floor. This should only be
+ being applied in areas where noise dominates masking;
+ otherwise we don't want to be adding tones back. */
+ double val=mask[p]*mask[p]+current_SL;
if(val<original_SL){
addcount++;
if(f[p]>0)
- work[p]=1.;
+ work[p]=mask[p]/flr[p];
else
- work[p]=-1.;
+ work[p]=-mask[p]/flr[p];
current_SL=val;
}else
break;
@@ -497,24 +531,27 @@ void _vp_apply_floor(vorbis_look_psy *p,double *f,
memcpy(f,work,p->n*sizeof(double));
}
-void _vp_tone_tone_mask(vorbis_look_psy *p,double *f, double *flr,
- double *decay){
+void _vp_tone_tone_mask(vorbis_look_psy *p,double *f,
+ double *flr, double *mask,
+ double *decay){
double *iter=alloca(sizeof(double)*p->n);
- int i,j;
+ int i,j,n=p->n;
+
+ for(i=0;i<n;i++)iter[i]=fabs(f[i]);
- for(i=0;i<p->n;i++)iter[i]=fabs(f[i]);
+ /* perform iterative tone-tone masking */
for(i=0;i<p->vi->curve_fit_iterations;i++){
if(i==0)
- _vp_tone_tone_iter(p,iter,flr,decay);
+ _vp_tone_tone_iter(p,iter,flr,mask,decay);
else{
- _vp_tone_tone_iter(p,iter,iter,decay);
- for(j=0;j<p->n;j++)
+ _vp_tone_tone_iter(p,iter,iter,mask,decay);
+ for(j=0;j<n;j++)
flr[j]=(flr[j]+iter[j])/2.;
}
if(i!=p->vi->curve_fit_iterations-1){
- for(j=0;j<p->n;j++)
- if(fabs(f[j])<flr[j])
+ for(j=0;j<n;j++)
+ if(fabs(f[j])<mask[j] && fabs(f[j])<flr[j])
iter[j]=0.;
else
iter[j]=fabs(f[j]);
diff --git a/lib/psy.h b/lib/psy.h
index ef80ad83..1b7bd1b4 100644
--- a/lib/psy.h
+++ b/lib/psy.h
@@ -12,7 +12,7 @@
********************************************************************
function: random psychoacoustics (not including preecho)
- last mod: $Id: psy.h,v 1.11.2.2.2.2 2000/03/30 11:46:18 xiphmont Exp $
+ last mod: $Id: psy.h,v 1.11.2.2.2.3 2000/04/21 16:35:39 xiphmont Exp $
********************************************************************/
@@ -41,9 +41,11 @@ extern void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi,int n,long rat
extern void _vp_psy_clear(vorbis_look_psy *p);
extern void *_vi_psy_dup(void *source);
extern void _vi_psy_free(vorbis_info_psy *i);
-extern void _vp_tone_tone_mask(vorbis_look_psy *p,double *f, double *floor,
+extern void _vp_tone_tone_mask(vorbis_look_psy *p,double *f,
+ double *floor, double *mask,
double *decay);
-extern void _vp_apply_floor(vorbis_look_psy *p,double *f,double *flr);
+extern void _vp_apply_floor(vorbis_look_psy *p,double *f,
+ double *flr,double *mask);
#endif
diff --git a/lib/psytune.c b/lib/psytune.c
index b515df39..e5d9e6d9 100644
--- a/lib/psytune.c
+++ b/lib/psytune.c
@@ -13,7 +13,7 @@
function: simple utility that runs audio through the psychoacoustics
without encoding
- last mod: $Id: psytune.c,v 1.1.2.2.2.5 2000/04/06 15:59:37 xiphmont Exp $
+ last mod: $Id: psytune.c,v 1.1.2.2.2.6 2000/04/21 16:35:39 xiphmont Exp $
********************************************************************/
@@ -33,7 +33,7 @@
static vorbis_info_psy _psy_set0={
1,1,1,
- 1,16,4.,
+ 1,8,4.,
-130.,
@@ -44,19 +44,14 @@ static vorbis_info_psy _psy_set0={
{-35.,-40.,-60.,-80.,-100.},
{-35.,-40.,-60.,-80.,-100.},
- /*{-99,-99,-99,-99,-99},
- {-99,-99,-99,-99,-99},
- {-99,-99,-99,-99,-99},
- {-99,-99,-99,-99,-99},
- {-99,-99,-99,-99,-99},
- {-99,-99,-99,-99,-99},*/
- {-8.,-12.,-18.,-20.,-24.},
- {-8.,-12.,-18.,-20.,-24.},
- {-8.,-12.,-18.,-20.,-24.},
- {-8.,-12.,-18.,-20.,-24.},
- {-8.,-12.,-18.,-20.,-24.},
- {-8.,-12.,-18.,-20.,-24.},
- -20.,-10.,
+ 1,
+ {{-6.,-8.,-12.,-16.,-18.},
+ {-6.,-8.,-12.,-16.,-18.},
+ {-6.,-8.,-12.,-16.,-18.},
+ {-6.,-8.,-12.,-16.,-20.},
+ {-6.,-8.,-12.,-16.,-20.},
+ {-6.,-8.,-10.,-14.,-18.},},
+ -80.,-40.,
110.,
@@ -92,8 +87,42 @@ void analysis(char *base,int i,double *v,int n,int bark,int dB){
}
}
+typedef struct {
+ long n;
+ int ln;
+ int m;
+ int *linearmap;
+
+ vorbis_info_floor0 *vi;
+ lpc_lookup lpclook;
+} vorbis_look_floor0;
+
+extern double _curve_to_lpc(double *curve,double *lpc,vorbis_look_floor0 *l,
+ long frameno);
+extern void _lpc_to_curve(double *curve,double *lpc,double amp,
+ vorbis_look_floor0 *l,char *name,long frameno);
+
long frameno=0;
+/* hacked from floor0.c */
+static void floorinit(vorbis_look_floor0 *look,int n,int m,int ln){
+ int j;
+ double scale;
+ look->m=m;
+ look->n=n;
+ look->ln=ln;
+ lpc_init(&look->lpclook,look->ln,look->m);
+
+ scale=look->ln/toBARK(22050.);
+
+ look->linearmap=malloc(look->n*sizeof(int));
+ for(j=0;j<look->n;j++){
+ int val=floor( toBARK(22050./n*j) *scale);
+ if(val>look->ln)val=look->ln;
+ look->linearmap[j]=val;
+ }
+}
+
int main(int argc,char *argv[]){
int eos=0;
double nonz=0.;
@@ -103,13 +132,13 @@ int main(int argc,char *argv[]){
int framesize=2048;
int order=32;
- double *pcm[2],*out[2],*window,*mask,*maskwindow,*decay[2],*lpc,*floor;
+ double *pcm[2],*out[2],*window,*mask,*decay[2],*lpc,*floor;
signed char *buffer,*buffer2;
mdct_lookup m_look;
vorbis_look_psy p_look;
long i,j,k;
- lpc_lookup lpc_look;
+ vorbis_look_floor0 floorlook;
int ath=0;
int decayp=0;
@@ -164,18 +193,14 @@ int main(int argc,char *argv[]){
buffer=malloc(framesize*4);
buffer2=buffer+framesize*2;
window=_vorbis_window(0,framesize,framesize/2,framesize/2);
- maskwindow=_vorbis_window(0,framesize,framesize/2,framesize/2);
mdct_init(&m_look,framesize);
_vp_psy_init(&p_look,&_psy_set0,framesize/2,44100);
- lpc_init(&lpc_look,framesize/2,order);
+ floorinit(&floorlook,framesize/2,order,framesize/8);
for(i=0;i<11;i++)
for(j=0;j<9;j++)
analysis("Pcurve",i*10+j,p_look.curves[i][j],EHMER_MAX,0,1);
- for(j=0;j<framesize;j++)
- maskwindow[j]*=maskwindow[j];
-
/* we cheat on the WAV header; we just bypass 44 bytes and never
verify that it matches 16bit/stereo/44.1kHz. */
@@ -203,47 +228,30 @@ int main(int argc,char *argv[]){
}
for(i=0;i<2;i++){
+ double amp;
analysis("pre",frameno,pcm[i],framesize,0,0);
/* do the psychacoustics */
memset(mask,0,sizeof(double)*framesize/2);
for(j=0;j<framesize;j++)
- mask[j]=pcm[i][j]*maskwindow[j];
+ pcm[i][j]*=window[j];
- mdct_forward(&m_look,mask,mask);
+ mdct_forward(&m_look,pcm[i],pcm[i]);
- analysis("maskmdct",frameno,mask,framesize/2,1,1);
+ analysis("mdct",frameno,pcm[i],framesize/2,1,1);
- _vp_tone_tone_mask(&p_look,mask,floor,decay[i]);
+ _vp_tone_tone_mask(&p_look,pcm[i],floor,mask,decay[i]);
- analysis("mask",frameno,floor,framesize/2,1,1);
- analysis("lmask",frameno,floor,framesize/2,0,1);
+ analysis("mask",frameno,mask,framesize/2,1,1);
+ analysis("prefloor",frameno,floor,framesize/2,1,1);
analysis("decay",frameno,decay[i],framesize/2,1,1);
- analysis("ldecay",frameno,decay[i],framesize/2,0,1);
- for(j=0;j<framesize;j++)
- pcm[i][j]=pcm[i][j]*window[j];
- analysis("pcm",frameno,pcm[i],framesize,0,0);
-
- mdct_forward(&m_look,pcm[i],pcm[i]);
- analysis("mdct",frameno,pcm[i],framesize/2,1,1);
- analysis("lmdct",frameno,pcm[i],framesize/2,0,1);
-
- /* floor */
- /*{
- double amp;
-
- for(j=0;j<framesize/2;j++)floor[j]=todB(floor[j])+DYNAMIC_RANGE_dB;
- amp=sqrt(vorbis_curve_to_lpc(floor,lpc,&lpc_look));
- fprintf(stderr,"amp=%g\n",amp);
- vorbis_lpc_to_curve(floor,lpc,amp,&lpc_look);
- for(j=0;j<framesize/2;j++)floor[j]=fromdB(floor[j]-DYNAMIC_RANGE_dB);
- analysis("floor",frameno,floor,framesize/2,1,1);
-
- }*/
+ amp=_curve_to_lpc(floor,lpc,&floorlook,frameno);
+ _lpc_to_curve(floor,lpc,sqrt(amp),&floorlook,"Ffloor",frameno);
+ analysis("floor",frameno,floor,framesize/2,1,1);
- _vp_apply_floor(&p_look,pcm[i],floor);
+ _vp_apply_floor(&p_look,pcm[i],floor,mask);
/* re-add floor */
for(j=0;j<framesize/2;j++){
diff --git a/lib/res0.c b/lib/res0.c
index 52208b16..ec7a5670 100644
--- a/lib/res0.c
+++ b/lib/res0.c
@@ -12,7 +12,7 @@
********************************************************************
function: residue backend 0 implementation
- last mod: $Id: res0.c,v 1.8.4.4 2000/04/13 04:53:04 xiphmont Exp $
+ last mod: $Id: res0.c,v 1.8.4.5 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
@@ -38,12 +38,7 @@ typedef struct {
int parts;
codebook *phrasebook;
-
codebook ***partbooks;
- int *partstages;
-
- double *partlevels;
- int *partgrouping;
int partvals;
int **decodemap;
@@ -63,12 +58,9 @@ void free_look(vorbis_look_residue *i){
for(j=0;j<look->parts;j++)
if(look->partbooks[j])free(look->partbooks[j]);
free(look->partbooks);
- free(look->partlevels);
- free(look->partgrouping);
for(j=0;j<look->partvals;j++)
free(look->decodemap[j]);
free(look->decodemap);
- if(look->partstages)free(look->partstages);
memset(i,0,sizeof(vorbis_look_residue0));
free(i);
}
@@ -86,6 +78,9 @@ void pack(vorbis_info_residue *vr,oggpack_buffer *opb){
_oggpack_write(opb,info->groupbook,8); /* group huffman book */
for(j=0;j<info->partitions;j++){
_oggpack_write(opb,info->secondstages[j],4); /* zero *is* a valid choice */
+ /* bit of 0 == additive, 1 == multiplicative cascade */
+ if(info->secondstages[j]>1)
+ _oggpack_write(opb,info->addmullist[j],info->secondstages[j]-1);
acc+=info->secondstages[j];
}
for(j=0;j<acc;j++)
@@ -103,8 +98,13 @@ vorbis_info_residue *unpack(vorbis_info *vi,oggpack_buffer *opb){
info->grouping=_oggpack_read(opb,24)+1;
info->partitions=_oggpack_read(opb,6)+1;
info->groupbook=_oggpack_read(opb,8);
- for(j=0;j<info->partitions;j++)
+ for(j=0;j<info->partitions;j++){
acc+=info->secondstages[j]=_oggpack_read(opb,4);
+ if(info->secondstages[j]>1)
+ info->addmullist[j]=_oggpack_read(opb,info->secondstages[j]-1);
+ else
+ info->addmullist[j]=0;
+ }
for(j=0;j<acc;j++)
info->booklist[j]=_oggpack_read(opb,8);
@@ -131,9 +131,6 @@ vorbis_look_residue *look (vorbis_dsp_state *vd,vorbis_info_mode *vm,
dim=look->phrasebook->dim;
look->partbooks=calloc(look->parts,sizeof(codebook **));
- look->partlevels=calloc(look->parts,sizeof(double));
- look->partgrouping=calloc(look->parts,sizeof(int));
- look->partstages=calloc(look->parts,sizeof(int));
for(j=0;j<look->parts;j++){
int stages=info->secondstages[j];
@@ -142,12 +139,9 @@ vorbis_look_residue *look (vorbis_dsp_state *vd,vorbis_info_mode *vm,
for(k=0;k<stages;k++)
look->partbooks[j][k]=vd->fullbooks+info->booklist[acc++];
}
- look->partgrouping[j]=_ilog(info->partinterl[j])-1;
- look->partlevels[j]=info->partlevels[j];
- look->partstages[j]=stages;
}
- look->partvals=pow(look->parts,dim);
+ look->partvals=rint(pow(look->parts,dim));
look->decodemap=malloc(look->partvals*sizeof(int *));
for(j=0;j<look->partvals;j++){
long val=j;
@@ -164,78 +158,76 @@ vorbis_look_residue *look (vorbis_dsp_state *vd,vorbis_info_mode *vm,
return(look);
}
-/* does not guard against invalid settings; eg, a subn of 16 and a
- subgroup request of 32. Max subn of 128 */
+/* classify by max quantized amplitude only */
static int _testhack(double *vec,int n,vorbis_look_residue0 *look){
- int i,j=0;
+ vorbis_info_residue0 *info=look->info;
double max=0.;
- double entropy[8];
- double temp[128];
-
- /* setup */
- for(i=0;i<n;i++){
- if(vec[i])
- temp[i]=(todB(vec[i])+6.);
- else
- temp[i]=0.;
- }
-
- /* handle case subgrp==1 outside */
+ int i;
+
for(i=0;i<n;i++)
- if(temp[i]>max)max=temp[i];
-
- while(1){
- entropy[j]=max; /* in the encoder, we're comparing against
- non-normalized vals to save cycles */
- n>>=1;
- j++;
-
- if(n<=0)break;
- for(i=0;i<n;i++){
- temp[i]+=temp[i+n];
- }
- max=0.;
- for(i=0;i<n;i++)
- if(temp[i]>max)max=temp[i];
- }
-
+ if(fabs(vec[i])>max)max=fabs(vec[i]);
+
for(i=0;i<look->parts-1;i++)
- if(entropy[look->partgrouping[i]]>look->partlevels[i])
+ if(max>=info->ampmax[i])
break;
return(i);
}
static int _encodepart(oggpack_buffer *opb,double *vec, int n,
- int stages, codebook **books){
- int i,j,o,bits=0;
+ int stages, int addmul, codebook **books){
+ int i,j,bits=0;
double *work=alloca(n*sizeof(double));
+
+ /* pessimistic, but safe */
+ long *stackword=alloca(n*stages*sizeof(long));
+ int *stacklen=alloca(n*stages*sizeof(int));
+ int stack=0;
+
memcpy(work,vec,n*sizeof(double));
+ /* The stages are listed in *decode* order; although the stages have
+ to decode this way, if the encode process is to use the same
+ setup data as the decode process we need to run encode backwards
+ into a stack, then write the entries out */
+
/* If we have n samples, but book dim in m (<n), we interlace the
samples we actually encode */
- for(j=0;j<stages;j++){
+ for(j=stages-1;j>=0;j--){
int dim=books[j]->dim;
int step=n/dim;
- for(i=0,o=0;i<n;i+=dim,o++)
- bits+=vorbis_book_encodevEs(books[j],work+o,opb,step);
+ for(i=step-1;i>=0;i--){
+ int entry=vorbis_book_besterror(books[j],work+i,step,(addmul>>j)&1);
+ stackword[stack]=vorbis_book_codeword(books[j],entry);
+ bits+=stacklen[stack++]=vorbis_book_codelen(books[j],entry);
+ }
+ }
+
+ while(stack){
+ stack--;
+ _oggpack_write(opb,stackword[stack],stacklen[stack]);
}
return(bits);
}
static int _decodepart(oggpack_buffer *opb,double *work,double *vec, int n,
- int stages, codebook **books){
+ int stages, int addmul,codebook **books){
int i,j,o;
memset(work,0,n*sizeof(double));
for(j=0;j<stages;j++){
int dim=books[j]->dim;
int step=n/dim;
- for(i=0,o=0;i<n;i+=dim,o++)
- vorbis_book_decodevs(books[j],work+o,opb,step);
+ if(j)
+ for(i=0,o=0;i<n;i+=dim,o++)
+ vorbis_book_decodevs(books[j],work+o,opb,step,(addmul>>(j-1))&1);
+ else
+ for(i=0,o=0;i<n;i+=dim,o++)
+ vorbis_book_decodevs(books[j],work+o,opb,step,-1);
+
}
-
+
for(i=0;i<n;i++)
vec[i]*=work[i];
@@ -298,7 +290,8 @@ int forward(vorbis_block *vb,vorbis_look_residue *vl,
for(j=0;j<ch;j++){
resbits[partword[j][l]]+=
_encodepart(&vb->opb,in[j]+i,samples_per_partition,
- look->partstages[partword[j][l]],
+ info->secondstages[partword[j][l]],
+ info->addmullist[partword[j][l]],
look->partbooks[partword[j][l]]);
resvals[partword[j][l]]+=samples_per_partition;
}
@@ -312,7 +305,7 @@ int forward(vorbis_block *vb,vorbis_look_residue *vl,
for(i=0;i<possible_partitions;i++)
fprintf(stderr,"%ld(%ld):%ld ",i,resvals[i],resbits[i]);
fprintf(stderr,"\n");
-
+
return(0);
}
@@ -345,7 +338,8 @@ int inverse(vorbis_block *vb,vorbis_look_residue *vl,double **in,int ch){
for(j=0;j<ch;j++){
int part=partword[j][k];
_decodepart(&vb->opb,work,in[j]+i,samples_per_partition,
- look->partstages[part],
+ info->secondstages[part],
+ info->addmullist[partword[j][l]],
look->partbooks[part]);
}
}
diff --git a/lib/sharedbook.c b/lib/sharedbook.c
index 4621a9ae..0c144bcc 100644
--- a/lib/sharedbook.c
+++ b/lib/sharedbook.c
@@ -12,7 +12,7 @@
********************************************************************
function: basic shared codebook operations
- last mod: $Id: sharedbook.c,v 1.1.2.4 2000/04/13 04:53:04 xiphmont Exp $
+ last mod: $Id: sharedbook.c,v 1.1.2.5 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
@@ -68,7 +68,7 @@ double _float32_unpack(long val){
/* given a list of word lengths, generate a list of codewords. Works
for length ordered or unordered, always assigns the lowest valued
- codewords first */
+ codewords first. Extended to handle unused entries (length 0) */
long *_make_words(long *l,long n){
long i,j;
long marker[33];
@@ -77,50 +77,52 @@ long *_make_words(long *l,long n){
for(i=0;i<n;i++){
long length=l[i];
- long entry=marker[length];
-
- /* when we claim a node for an entry, we also claim the nodes
- below it (pruning off the imagined tree that may have dangled
- from it) as well as blocking the use of any nodes directly
- above for leaves */
-
- /* update ourself */
- if(length<32 && (entry>>length)){
- /* error condition; the lengths must specify an overpopulated tree */
- free(r);
- return(NULL);
- }
- r[i]=entry;
+ if(length>0){
+ long entry=marker[length];
+
+ /* when we claim a node for an entry, we also claim the nodes
+ below it (pruning off the imagined tree that may have dangled
+ from it) as well as blocking the use of any nodes directly
+ above for leaves */
+
+ /* update ourself */
+ if(length<32 && (entry>>length)){
+ /* error condition; the lengths must specify an overpopulated tree */
+ free(r);
+ return(NULL);
+ }
+ r[i]=entry;
- /* Look to see if the next shorter marker points to the node
- above. if so, update it and repeat. */
- {
- for(j=length;j>0;j--){
-
- if(marker[j]&1){
- /* have to jump branches */
- if(j==1)
- marker[1]++;
- else
- marker[j]=marker[j-1]<<1;
- break; /* invariant says next upper marker would already
- have been moved if it was on the same path */
+ /* Look to see if the next shorter marker points to the node
+ above. if so, update it and repeat. */
+ {
+ for(j=length;j>0;j--){
+
+ if(marker[j]&1){
+ /* have to jump branches */
+ if(j==1)
+ marker[1]++;
+ else
+ marker[j]=marker[j-1]<<1;
+ break; /* invariant says next upper marker would already
+ have been moved if it was on the same path */
+ }
+ marker[j]++;
}
- marker[j]++;
}
- }
-
- /* prune the tree; the implicit invariant says all the longer
- markers were dangling from our just-taken node. Dangle them
- from our *new* node. */
- for(j=length+1;j<33;j++)
- if((marker[j]>>1) == entry){
- entry=marker[j];
- marker[j]=marker[j-1]<<1;
- }else
- break;
+
+ /* prune the tree; the implicit invariant says all the longer
+ markers were dangling from our just-taken node. Dangle them
+ from our *new* node. */
+ for(j=length+1;j<33;j++)
+ if((marker[j]>>1) == entry){
+ entry=marker[j];
+ marker[j]=marker[j-1]<<1;
+ }else
+ break;
+ }
}
-
+
/* bitreverse the words because our bitwise packer/unpacker is LSb
endian */
for(i=0;i<n;i++){
@@ -148,84 +150,131 @@ decode_aux *_make_decode_tree(codebook *c){
t->aux=c->entries*2;
for(i=0;i<c->entries;i++){
- long ptr=0;
- for(j=0;j<s->lengthlist[i]-1;j++){
- int bit=(codelist[i]>>j)&1;
- if(!bit){
- if(!ptr0[ptr])
- ptr0[ptr]= ++top;
- ptr=ptr0[ptr];
- }else{
- if(!ptr1[ptr])
- ptr1[ptr]= ++top;
- ptr=ptr1[ptr];
+ if(s->lengthlist[i]>0){
+ long ptr=0;
+ for(j=0;j<s->lengthlist[i]-1;j++){
+ int bit=(codelist[i]>>j)&1;
+ if(!bit){
+ if(!ptr0[ptr])
+ ptr0[ptr]= ++top;
+ ptr=ptr0[ptr];
+ }else{
+ if(!ptr1[ptr])
+ ptr1[ptr]= ++top;
+ ptr=ptr1[ptr];
+ }
}
+ if(!((codelist[i]>>j)&1))
+ ptr0[ptr]=-i;
+ else
+ ptr1[ptr]=-i;
}
- if(!((codelist[i]>>j)&1))
- ptr0[ptr]=-i;
- else
- ptr1[ptr]=-i;
}
free(codelist);
return(t);
}
+/* there might be a straightforward one-line way to do the below
+ that's portable and totally safe against roundoff, but I haven't
+ thought of it. Therefore, we opt on the side of caution */
+long _book_maptype1_quantvals(const static_codebook *b){
+ long vals=floor(pow(b->entries,1./b->dim));
+
+ /* the above *should* be reliable, but we'll not assume that FP is
+ ever reliable when bitstream sync is at stake; verify via integer
+ means that vals really is the greatest value of dim for which
+ vals^b->bim <= b->entries */
+ /* treat the above as an initial guess */
+ while(1){
+ long acc=1;
+ long acc1=1;
+ int i;
+ for(i=0;i<b->dim;i++){
+ acc*=vals;
+ acc1*=vals+1;
+ }
+ if(acc<=b->entries && acc1>b->entries){
+ return(vals);
+ }else{
+ if(acc>b->entries){
+ vals--;
+ }else{
+ vals++;
+ }
+ }
+ }
+}
+
/* unpack the quantized list of values for encode/decode ***********/
+/* we need to deal with two map types: in map type 1, the values are
+ generated algorithmically (each column of the vector counts through
+ the values in the quant vector). in map type 2, all the values came
+ in in an explicit list. Both value lists must be unpacked */
double *_book_unquantize(const static_codebook *b){
long j,k;
- if(b->quantlist){
+ if(b->maptype==1 || b->maptype==2){
+ int quantvals;
double mindel=_float32_unpack(b->q_min);
double delta=_float32_unpack(b->q_delta);
- double *r=malloc(sizeof(double)*b->entries*b->dim);
-
- for(j=0;j<b->entries;j++){
- double last=0.;
- for(k=0;k<b->dim;k++){
- double val=b->quantlist[j*b->dim+k];
- if(val!=0){
- val=(fabs(val)-1.)*delta+mindel+last;
+ double *r=calloc(b->entries*b->dim,sizeof(double));
+
+ /* maptype 1 and 2 both use a quantized value vector, but
+ different sizes */
+ switch(b->maptype){
+ case 1:
+ /* most of the time, entries%dimensions == 0, but we need to be
+ well defined. We define that the possible vales at each
+ scalar is values == entries/dim. If entries%dim != 0, we'll
+ have 'too few' values (values*dim<entries), which means that
+ we'll have 'left over' entries; left over entries use zeroed
+ values (and are wasted). So don't generate codebooks like
+ that */
+ quantvals=_book_maptype1_quantvals(b);
+ for(j=0;j<b->entries;j++){
+ double last=0.;
+ int indexdiv=1;
+ for(k=0;k<b->dim;k++){
+ int index= (j/indexdiv)%quantvals;
+ double val=b->quantlist[index];
+ val=fabs(val)*delta+mindel+last;
if(b->q_sequencep)last=val;
- if(b->q_log)val=fromdB(val);
- if(b->quantlist[j*b->dim+k]<0)val= -val;
+ r[j*b->dim+k]=val;
+ indexdiv*=quantvals;
}
- r[j*b->dim+k]=val;
}
- }
- return(r);
- }else
- return(NULL);
-}
-
-/* on the encode side of a log scale, we need both the linear
- representation (done by unquantize above) but also a log version to
- speed error metric computation */
-double *_book_logdist(const static_codebook *b,double *vals){
- long j;
- if(b->quantlist && b->q_log){
- double *r=malloc(sizeof(double)*b->entries*b->dim);
- for(j=0;j<b->entries*b->dim;j++){
- if(vals[j]==0){
- r[j]=0.;
- }else{
- r[j]=todB(vals[j])+b->q_encodebias;
- if(vals[j]<0)r[j]= -r[j];
+ break;
+ case 2:
+ for(j=0;j<b->entries;j++){
+ double last=0.;
+ for(k=0;k<b->dim;k++){
+ double val=b->quantlist[j*b->dim+k];
+ val=fabs(val)*delta+mindel+last;
+ if(b->q_sequencep)last=val;
+ r[j*b->dim+k]=val;
+ }
}
}
return(r);
- }else
- return(NULL);
+ }
+ return(NULL);
}
void vorbis_staticbook_clear(static_codebook *b){
if(b->quantlist)free(b->quantlist);
if(b->lengthlist)free(b->lengthlist);
- if(b->encode_tree){
- free(b->encode_tree->ptr0);
- free(b->encode_tree->ptr1);
- free(b->encode_tree->p);
- free(b->encode_tree->q);
- memset(b->encode_tree,0,sizeof(encode_aux));
- free(b->encode_tree);
+ if(b->nearest_tree){
+ free(b->nearest_tree->ptr0);
+ free(b->nearest_tree->ptr1);
+ free(b->nearest_tree->p);
+ free(b->nearest_tree->q);
+ memset(b->nearest_tree,0,sizeof(encode_aux_nearestmatch));
+ free(b->nearest_tree);
+ }
+ if(b->thresh_tree){
+ free(b->thresh_tree->quantthresh);
+ free(b->thresh_tree->quantmap);
+ memset(b->thresh_tree,0,sizeof(encode_aux_threshmatch));
+ free(b->thresh_tree);
}
memset(b,0,sizeof(static_codebook));
}
@@ -240,7 +289,6 @@ void vorbis_book_clear(codebook *b){
free(b->decode_tree);
}
if(b->valuelist)free(b->valuelist);
- if(b->logdist)free(b->logdist);
if(b->codelist)free(b->codelist);
memset(b,0,sizeof(codebook));
}
@@ -252,7 +300,6 @@ int vorbis_book_init_encode(codebook *c,const static_codebook *s){
c->dim=s->dim;
c->codelist=_make_words(s->lengthlist,s->entries);
c->valuelist=_book_unquantize(s);
- c->logdist=_book_logdist(s,c->valuelist);
return(0);
}
@@ -271,26 +318,48 @@ int vorbis_book_init_decode(codebook *c,const static_codebook *s){
}
int _best(codebook *book, double *a, int step){
- encode_aux *t=book->c->encode_tree;
+ encode_aux_nearestmatch *nt=book->c->nearest_tree;
+ encode_aux_threshmatch *tt=book->c->thresh_tree;
int dim=book->dim;
int ptr=0,k,o;
- /* optimized using the decision tree */
- while(1){
- double c=0.;
- double *p=book->valuelist+t->p[ptr];
- double *q=book->valuelist+t->q[ptr];
-
- for(k=0,o=0;k<dim;k++,o+=step)
- c+=(p[k]-q[k])*(a[o]-(p[k]+q[k])*.5);
-
- if(c>0.) /* in A */
- ptr= -t->ptr0[ptr];
- else /* in B */
- ptr= -t->ptr1[ptr];
- if(ptr<=0)break;
+ if(nt){
+ /* optimized using the decision tree */
+ while(1){
+ double c=0.;
+ double *p=book->valuelist+nt->p[ptr];
+ double *q=book->valuelist+nt->q[ptr];
+
+ for(k=0,o=0;k<dim;k++,o+=step)
+ c+=(p[k]-q[k])*(a[o]-(p[k]+q[k])*.5);
+
+ if(c>0.) /* in A */
+ ptr= -nt->ptr0[ptr];
+ else /* in B */
+ ptr= -nt->ptr1[ptr];
+ if(ptr<=0)break;
+ }
+ return(-ptr);
+ }
+
+ /* we assume for now that a thresh tree is the only other possibility */
+ if(tt){
+ int index=0;
+ /* find the quant val of each scalar */
+ for(k=0,o=step*(dim-1);k<dim;k++,o-=step){
+ int i;
+ /* linear search the quant list for now; it's small and although
+ with > 8 entries, it would be faster to bisect, this would be
+ a misplaced optimization for now */
+ for(i=0;i<tt->quantvals-1;i++)
+ if(a[o]<tt->quantthresh[i])break;
+
+ index=(index*tt->quantvals)+tt->quantmap[i];
+ }
+ /* regular lattices are easy :-) */
+ return(index);
}
- return(-ptr);
+ return(-1);
}
static double _dist(int el,double *a, double *b){
@@ -303,51 +372,170 @@ static double _dist(int el,double *a, double *b){
return(acc);
}
-int _logbest(codebook *book, double *a, int step){
- encode_aux *t=book->c->encode_tree;
- int dim=book->dim;
- int ptr=0,k,o;
- double *loga=alloca(sizeof(double)*dim);
- double bias=book->c->q_encodebias;
+/* returns the entry number and *modifies a* to the remainder value ********/
+int vorbis_book_besterror(codebook *book,double *a,int step,int addmul){
+ int dim=book->dim,i,o;
+ int best=_best(book,a,step);
+ switch(addmul){
+ case 0:
+ for(i=0,o=0;i<dim;i++,o+=step)
+ a[o]-=(book->valuelist+best*dim)[i];
+ break;
+ case 1:
+ for(i=0,o=0;i<dim;i++,o+=step){
+ double val=(book->valuelist+best*dim)[i];
+ if(val==0){
+ a[o]=0;
+ }else{
+ a[o]/=val;
+ }
+ }
+ break;
+ }
+ return(best);
+}
+
+long vorbis_book_codeword(codebook *book,int entry){
+ return book->codelist[entry];
+}
+
+long vorbis_book_codelen(codebook *book,int entry){
+ return book->c->lengthlist[entry];
+}
+
+#ifdef _V_SELFTEST
+
+/* Unit tests of the dequantizer; this stuff will be OK
+ cross-platform, I simply want to be sure that special mapping cases
+ actually work properly; a bug could go unnoticed for a while */
+
+#include <stdio.h>
+
+/* cases:
+
+ no mapping
+ full, explicit mapping
+ algorithmic mapping
+
+ nonsequential
+ sequential
+*/
+
+static long full_quantlist1[]={0,1,2,3, 4,5,6,7, 8,3,6,1};
+static long partial_quantlist1[]={0,7,2};
+
+/* no mapping */
+static_codebook test1={
+ 4,16,
+ NULL,
+ 0,
+ 0,0,0,0,
+ NULL,
+ NULL,NULL
+};
+static double *test1_result=NULL;
- for(k=0,o=0;k<dim;k++,o+=step)
- if(a[o]==0.)
- loga[k]=0.;
- else{
- loga[k]=todB(a[o])+bias;
- if(a[o]<0)loga[k]= -loga[k];
+/* linear, full mapping, nonsequential */
+static_codebook test2={
+ 4,3,
+ NULL,
+ 2,
+ -533200896,1611661312,4,0,
+ full_quantlist1,
+ NULL,NULL
+};
+static double test2_result[]={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2};
+
+/* linear, full mapping, sequential */
+static_codebook test3={
+ 4,3,
+ NULL,
+ 2,
+ -533200896,1611661312,4,1,
+ full_quantlist1,
+ NULL,NULL
+};
+static double test3_result[]={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6};
+
+/* linear, algorithmic mapping, nonsequential */
+static_codebook test4={
+ 3,27,
+ NULL,
+ 1,
+ -533200896,1611661312,4,0,
+ partial_quantlist1,
+ NULL,NULL
+};
+static double test4_result[]={-3,-3,-3, 4,-3,-3, -1,-3,-3,
+ -3, 4,-3, 4, 4,-3, -1, 4,-3,
+ -3,-1,-3, 4,-1,-3, -1,-1,-3,
+ -3,-3, 4, 4,-3, 4, -1,-3, 4,
+ -3, 4, 4, 4, 4, 4, -1, 4, 4,
+ -3,-1, 4, 4,-1, 4, -1,-1, 4,
+ -3,-3,-1, 4,-3,-1, -1,-3,-1,
+ -3, 4,-1, 4, 4,-1, -1, 4,-1,
+ -3,-1,-1, 4,-1,-1, -1,-1,-1};
+
+/* linear, algorithmic mapping, sequential */
+static_codebook test5={
+ 3,27,
+ NULL,
+ 1,
+ -533200896,1611661312,4,1,
+ partial_quantlist1,
+ NULL,NULL
+};
+static double test5_result[]={-3,-6,-9, 4, 1,-2, -1,-4,-7,
+ -3, 1,-2, 4, 8, 5, -1, 3, 0,
+ -3,-4,-7, 4, 3, 0, -1,-2,-5,
+ -3,-6,-2, 4, 1, 5, -1,-4, 0,
+ -3, 1, 5, 4, 8,12, -1, 3, 7,
+ -3,-4, 0, 4, 3, 7, -1,-2, 2,
+ -3,-6,-7, 4, 1, 0, -1,-4,-5,
+ -3, 1, 0, 4, 8, 7, -1, 3, 2,
+ -3,-4,-5, 4, 3, 2, -1,-2,-3};
+
+void run_test(static_codebook *b,double *comp){
+ double *out=_book_unquantize(b);
+ int i;
+
+ if(comp){
+ if(!out){
+ fprintf(stderr,"_book_unquantize incorrectly returned NULL\n");
+ exit(1);
}
-#if 1
- /* optimized using the decision tree */
- while(1){
- double c=0.;
- double *p=book->logdist+t->p[ptr];
- double *q=book->logdist+t->q[ptr];
-
- for(k=0;k<dim;k++)
- c+=(p[k]-q[k])*(loga[k]-(p[k]+q[k])*.5);
-
- if(c>0.) /* in A */
- ptr= -t->ptr0[ptr];
- else /* in B */
- ptr= -t->ptr1[ptr];
- if(ptr<=0)break;
- }
- return(-ptr);
-#else
- {
- int besti=0;
- double best=_dist(dim,loga,book->logdist);
- for(k=1;k<book->entries;k++){
- double val=_dist(dim,loga,book->logdist+k*dim);
- if(val<best){
- best=val;
- besti=k;
+ for(i=0;i<b->entries*b->dim;i++)
+ if(fabs(out[i]-comp[i])>.0001){
+ fprintf(stderr,"disagreement in unquantized and reference data:\n"
+ "position %d, %g != %g\n",i,out[i],comp[i]);
+ exit(1);
}
+
+ }else{
+ if(out){
+ fprintf(stderr,"_book_unquantize returned a value array: \n"
+ " correct result should have been NULL\n");
+ exit(1);
}
- return(besti);
}
-#endif
}
+int main(){
+ /* run the nine dequant tests, and compare to the hand-rolled results */
+ fprintf(stderr,"Dequant test 1... ");
+ run_test(&test1,test1_result);
+ fprintf(stderr,"OK\nDequant test 2... ");
+ run_test(&test2,test2_result);
+ fprintf(stderr,"OK\nDequant test 3... ");
+ run_test(&test3,test3_result);
+ fprintf(stderr,"OK\nDequant test 4... ");
+ run_test(&test4,test4_result);
+ fprintf(stderr,"OK\nDequant test 5... ");
+ run_test(&test5,test5_result);
+ fprintf(stderr,"OK\n\n");
+
+ return(0);
+}
+
+#endif
diff --git a/lib/sharedbook.h b/lib/sharedbook.h
index d986aad6..be1dd4cb 100644
--- a/lib/sharedbook.h
+++ b/lib/sharedbook.h
@@ -12,7 +12,7 @@
********************************************************************
function: basic shared codebook operations
- last mod: $Id: sharedbook.h,v 1.1.2.3 2000/04/06 15:59:37 xiphmont Exp $
+ last mod: $Id: sharedbook.h,v 1.1.2.4 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
@@ -31,7 +31,13 @@ extern double *_book_logdist(const static_codebook *b,double *vals);
extern double _float32_unpack(long val);
extern long _float32_pack(double val);
extern int _best(codebook *book, double *a, int step);
-extern int _logbest(codebook *book, double *a, int step);
extern int _ilog(unsigned int v);
+extern long _book_maptype1_quantvals(const static_codebook *b);
+
+extern int vorbis_book_besterror(codebook *book,double *a,int step,int addmul);
+extern long vorbis_book_codeword(codebook *book,int entry);
+extern long vorbis_book_codelen(codebook *book,int entry);
+
+
#endif
diff --git a/vq/Makefile.in b/vq/Makefile.in
index ac287d71..34a20603 100644
--- a/vq/Makefile.in
+++ b/vq/Makefile.in
@@ -1,4 +1,4 @@
-# $Id: Makefile.in,v 1.10.4.1 2000/04/04 07:08:44 xiphmont Exp $
+# $Id: Makefile.in,v 1.10.4.2 2000/04/21 16:35:40 xiphmont Exp $
###############################################################################
# #
@@ -29,7 +29,7 @@ HFILES = ../include/vorbis/codebook.h vqgen.h vqext.h bookutil.h
OFILES = vqgen.o vqsplit.o bookutil.o ../lib/sharedbook.o
ALLOFILES = $(OFILES) lspdata.o genericdata.o train.o build.o run.o\
- cascade.o partition.o metrics.o residuedata.o
+ cascade.o partition.o metrics.o residuedata.o latticebuild.o
all:
$(MAKE) target CFLAGS="$(OPT)"
@@ -40,7 +40,7 @@ debug:
profile:
$(MAKE) target CFLAGS="$(PROFILE)"
-target: lspvqtrain genericvqtrain residuevqtrain vqbuild vqcascade vqpartition vqmetrics
+target: lspvqtrain genericvqtrain residuevqtrain vqbuild vqcascade vqmetrics latticebuild
lspvqtrain: $(OFILES) lspdata.o train.o
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
@@ -57,12 +57,13 @@ vqbuild: $(OFILES) build.o
vqcascade: $(OFILES) run.o cascade.o
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
-vqpartition: $(OFILES) run.o partition.o
+vqmetrics: $(OFILES) run.o metrics.o
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
-vqmetrics: $(OFILES) run.o metrics.o
+latticebuild: $(OFILES) latticebuild.o
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
+
$(ALLOFILES): $(HFILES)
.c.o:
@@ -73,7 +74,7 @@ $(OFILES): $(HFILES)
clean:
-rm -f *.o *.a test* *~ *.out *.m config.* \
lspvqtrain genericvqtrain residuevqtrain\
- vqbuild vqmetrics vqpartition vqcascade
+ vqbuild vqmetrics latticebuild vqcascade
distclean: clean
-rm -f Makefile
diff --git a/vq/bookutil.c b/vq/bookutil.c
index f1093400..a1874859 100644
--- a/vq/bookutil.c
+++ b/vq/bookutil.c
@@ -12,7 +12,7 @@
********************************************************************
function: utility functions for loading .vqh and .vqd files
- last mod: $Id: bookutil.c,v 1.12.4.2 2000/04/13 04:53:04 xiphmont Exp $
+ last mod: $Id: bookutil.c,v 1.12.4.3 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
@@ -118,6 +118,13 @@ void reset_next_value(void){
v_sofar=0;
}
+char *setup_line(FILE *in){
+ reset_next_value();
+ value_line_buff=get_line(in);
+ return(value_line_buff);
+}
+
+
int get_vector(codebook *b,FILE *in,int start, int n,double *a){
int i;
const static_codebook *c=b->c;
@@ -173,12 +180,15 @@ char *find_seek_to(FILE *in,char *s){
codebook *codebook_load(char *filename){
codebook *b=calloc(1,sizeof(codebook));
static_codebook *c=(static_codebook *)(b->c=calloc(1,sizeof(static_codebook)));
- encode_aux *a=calloc(1,sizeof(encode_aux));
+ encode_aux_nearestmatch *a=NULL;
+ encode_aux_threshmatch *t=NULL;
+ int quant_to_read=0;
FILE *in=fopen(filename,"r");
char *line;
long i;
- c->encode_tree=a;
+ c->nearest_tree=a;
+ c->thresh_tree=t;
if(in==NULL){
fprintf(stderr,"Couldn't open codebook %s\n",filename);
@@ -190,39 +200,127 @@ codebook *codebook_load(char *filename){
/* get the major important values */
line=get_line(in);
- if(sscanf(line,"%ld, %ld, %d, %ld, %ld, %d, %d, %d, %d, %lf,",
- &(c->dim),&(c->entries),&(c->q_log),
- &(c->q_min),&(c->q_delta),&(c->q_quant),
- &(c->q_sequencep),
- &(c->q_zeroflag),&(c->q_negflag),
- &(c->q_encodebias))!=10){
+ if(sscanf(line,"%ld, %ld,",
+ &(c->dim),&(c->entries))!=2){
fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line);
exit(1);
}
-
- /* find the auxiliary encode struct (if any) */
- find_seek_to(in,"static encode_aux _vq_aux_");
- /* how big? */
- line=get_line(in);
line=get_line(in);
line=get_line(in);
- line=get_line(in);
- line=get_line(in);
- if(sscanf(line,"%ld, %ld",&(a->aux),&(a->alloc))!=2){
- fprintf(stderr,"2: syntax in %s in line:\t %s",filename,line);
+ if(sscanf(line,"%d, %ld, %ld, %d, %d,",
+ &(c->maptype),&(c->q_min),&(c->q_delta),&(c->q_quant),
+ &(c->q_sequencep))!=5){
+ fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line);
exit(1);
}
+
+ /* find the auxiliary encode struct[s] (if any) */
+ if(find_seek_to(in,"static encode_aux_nearestmatch _vq_aux_")){
+ /* how big? */
+ a=calloc(1,sizeof(encode_aux_nearestmatch));
+ line=get_line(in);
+ line=get_line(in);
+ line=get_line(in);
+ line=get_line(in);
+ line=get_line(in);
+ if(sscanf(line,"%ld, %ld",&(a->aux),&(a->alloc))!=2){
+ fprintf(stderr,"2: syntax in %s in line:\t %s",filename,line);
+ exit(1);
+ }
+
+ /* load ptr0 */
+ find_seek_to(in,"static long _vq_ptr0");
+ reset_next_value();
+ a->ptr0=malloc(sizeof(long)*a->aux);
+ for(i=0;i<a->aux;i++)
+ if(get_next_ivalue(in,a->ptr0+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+
+ /* load ptr1 */
+ find_seek_to(in,"static long _vq_ptr1");
+ reset_next_value();
+ a->ptr1=malloc(sizeof(long)*a->aux);
+ for(i=0;i<a->aux;i++)
+ if(get_next_ivalue(in,a->ptr1+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+
+
+ /* load p */
+ find_seek_to(in,"static long _vq_p_");
+ reset_next_value();
+ a->p=malloc(sizeof(long)*a->aux);
+ for(i=0;i<a->aux;i++)
+ if(get_next_ivalue(in,a->p+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+
+ /* load q */
+ find_seek_to(in,"static long _vq_q_");
+ reset_next_value();
+ a->q=malloc(sizeof(long)*a->aux);
+ for(i=0;i<a->aux;i++)
+ if(get_next_ivalue(in,a->q+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+ }
+
+ if(find_seek_to(in,"static encode_aux_threshmatch _vq_aux_")){
+ /* how big? */
+ t=calloc(1,sizeof(encode_aux_threshmatch));
+ line=get_line(in);
+ line=get_line(in);
+ if(sscanf(line,"%d",&(t->quantvals))!=1){
+ fprintf(stderr,"2: syntax in %s in line:\t %s",filename,line);
+ exit(1);
+ }
+ /* load quantthresh */
+ find_seek_to(in,"static long _vq_quantthresh_");
+ reset_next_value();
+ t->quantthresh=malloc(sizeof(long)*t->quantvals);
+ for(i=0;i<t->quantvals;i++)
+ if(get_next_value(in,t->quantthresh+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+ /* load quantmap */
+ find_seek_to(in,"static long _vq_quantmap_");
+ reset_next_value();
+ t->quantmap=malloc(sizeof(long)*t->quantvals);
+ for(i=0;i<t->quantvals;i++)
+ if(get_next_ivalue(in,t->quantmap+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+ }
+
+ switch(c->maptype){
+ case 0:
+ quant_to_read=0;
+ break;
+ case 1:
+ quant_to_read=_book_maptype1_quantvals(c);
+ break;
+ case 2:
+ quant_to_read=c->entries*c->dim;
+ break;
+ }
/* load the quantized entries */
find_seek_to(in,"static long _vq_quantlist_");
reset_next_value();
- c->quantlist=malloc(sizeof(long)*c->entries*c->dim);
- for(i=0;i<c->entries*c->dim;i++)
+ c->quantlist=malloc(sizeof(long)*quant_to_read);
+ for(i=0;i<quant_to_read;i++)
if(get_next_ivalue(in,c->quantlist+i)){
fprintf(stderr,"out of data while reading codebook %s\n",filename);
exit(1);
}
-
+
/* load the lengthlist */
find_seek_to(in,"static long _vq_lengthlist");
reset_next_value();
@@ -233,50 +331,9 @@ codebook *codebook_load(char *filename){
exit(1);
}
- /* load ptr0 */
- find_seek_to(in,"static long _vq_ptr0");
- reset_next_value();
- a->ptr0=malloc(sizeof(long)*a->aux);
- for(i=0;i<a->aux;i++)
- if(get_next_ivalue(in,a->ptr0+i)){
- fprintf(stderr,"out of data while reading codebook %s\n",filename);
- exit(1);
- }
-
- /* load ptr1 */
- find_seek_to(in,"static long _vq_ptr1");
- reset_next_value();
- a->ptr1=malloc(sizeof(long)*a->aux);
- for(i=0;i<a->aux;i++)
- if(get_next_ivalue(in,a->ptr1+i)){
- fprintf(stderr,"out of data while reading codebook %s\n",filename);
- exit(1);
- }
-
-
- /* load p */
- find_seek_to(in,"static long _vq_p_");
- reset_next_value();
- a->p=malloc(sizeof(long)*a->aux);
- for(i=0;i<a->aux;i++)
- if(get_next_ivalue(in,a->p+i)){
- fprintf(stderr,"out of data while reading codebook %s\n",filename);
- exit(1);
- }
-
- /* load q */
- find_seek_to(in,"static long _vq_q_");
- reset_next_value();
- a->q=malloc(sizeof(long)*a->aux);
- for(i=0;i<a->aux;i++)
- if(get_next_ivalue(in,a->q+i)){
- fprintf(stderr,"out of data while reading codebook %s\n",filename);
- exit(1);
- }
-
/* got it all */
fclose(in);
-
+
vorbis_book_init_encode(b,c);
return(b);
diff --git a/vq/bookutil.h b/vq/bookutil.h
index 3e7dd336..4c712270 100644
--- a/vq/bookutil.h
+++ b/vq/bookutil.h
@@ -12,7 +12,7 @@
********************************************************************
function: utility functions for loading .vqh and .vqd files
- last mod: $Id: bookutil.h,v 1.4.4.1 2000/04/04 07:08:45 xiphmont Exp $
+ last mod: $Id: bookutil.h,v 1.4.4.2 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
@@ -25,6 +25,7 @@
#include "vorbis/codebook.h"
extern char *get_line(FILE *in);
+extern char *setup_line(FILE *in);
extern int get_line_value(FILE *in,double *value);
extern int get_next_value(FILE *in,double *value);
extern int get_next_ivalue(FILE *in,long *ivalue);
diff --git a/vq/build.c b/vq/build.c
index 504333a8..41fd02f8 100644
--- a/vq/build.c
+++ b/vq/build.c
@@ -12,7 +12,7 @@
********************************************************************
function: utility main for building codebooks from training sets
- last mod: $Id: build.c,v 1.12.4.3 2000/04/13 04:53:04 xiphmont Exp $
+ last mod: $Id: build.c,v 1.12.4.4 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
@@ -22,6 +22,8 @@
#include <string.h>
#include <errno.h>
#include "vorbis/codebook.h"
+#include "../lib/sharedbook.h"
+#include "../lib/scales.h"
#include "vqgen.h"
#include "vqsplit.h"
@@ -135,8 +137,8 @@ int main(int argc,char *argv[]){
/* quant */
line=rline(in,out);
- if(sscanf(line,"%d %ld %ld %d %d %lf",&q.log,&q.min,&q.delta,
- &q.quant,&q.sequencep,&q.encodebias)!=6){
+ if(sscanf(line,"%ld %ld %d %d",&q.min,&q.delta,
+ &q.quant,&q.sequencep)!=4){
fprintf(stderr,"Syntax error reading book file\n");
exit(1);
}
@@ -179,10 +181,7 @@ int main(int argc,char *argv[]){
}
fclose(in);
-
- /* use our own because we want log training data to be linear for
- splitting */
- vqsp_unquantize(&v,&q);
+ vqgen_unquantize(&v,&q);
/* build the book */
vqsp_book(&v,&b,quantlist);
@@ -233,89 +232,64 @@ int main(int argc,char *argv[]){
/* ptr0 */
fprintf(out,"static long _vq_ptr0_%s[] = {\n",name);
- for(j=0;j<c.encode_tree->aux;){
+ for(j=0;j<c.nearest_tree->aux;){
fprintf(out,"\t");
- for(k=0;k<8 && j<c.encode_tree->aux;k++,j++)
- fprintf(out,"%6ld,",c.encode_tree->ptr0[j]);
+ for(k=0;k<8 && j<c.nearest_tree->aux;k++,j++)
+ fprintf(out,"%6ld,",c.nearest_tree->ptr0[j]);
fprintf(out,"\n");
}
fprintf(out,"};\n\n");
/* ptr1 */
fprintf(out,"static long _vq_ptr1_%s[] = {\n",name);
- for(j=0;j<c.encode_tree->aux;){
+ for(j=0;j<c.nearest_tree->aux;){
fprintf(out,"\t");
- for(k=0;k<8 && j<c.encode_tree->aux;k++,j++)
- fprintf(out,"%6ld,",c.encode_tree->ptr1[j]);
+ for(k=0;k<8 && j<c.nearest_tree->aux;k++,j++)
+ fprintf(out,"%6ld,",c.nearest_tree->ptr1[j]);
fprintf(out,"\n");
}
fprintf(out,"};\n\n");
/* p */
fprintf(out,"static long _vq_p_%s[] = {\n",name);
- for(j=0;j<c.encode_tree->aux;){
+ for(j=0;j<c.nearest_tree->aux;){
fprintf(out,"\t");
- for(k=0;k<8 && j<c.encode_tree->aux;k++,j++)
- fprintf(out,"%6ld,",c.encode_tree->p[j]*c.dim);
+ for(k=0;k<8 && j<c.nearest_tree->aux;k++,j++)
+ fprintf(out,"%6ld,",c.nearest_tree->p[j]*c.dim);
fprintf(out,"\n");
}
fprintf(out,"};\n\n");
/* q */
fprintf(out,"static long _vq_q_%s[] = {\n",name);
- for(j=0;j<c.encode_tree->aux;){
+ for(j=0;j<c.nearest_tree->aux;){
fprintf(out,"\t");
- for(k=0;k<8 && j<c.encode_tree->aux;k++,j++)
- fprintf(out,"%6ld,",c.encode_tree->q[j]*c.dim);
+ for(k=0;k<8 && j<c.nearest_tree->aux;k++,j++)
+ fprintf(out,"%6ld,",c.nearest_tree->q[j]*c.dim);
fprintf(out,"\n");
}
fprintf(out,"};\n\n");
- /* zero quant values? Negative log quant values? */
- {
- int zero=0;
- int neg=0;
- for(j=0;j<c.entries*dim;j++){
- if(c.quantlist[j]==0){
- if(q.log)
- zero=1;
- else{
- fprintf(stderr,"INTERNAL ERROR: Non log scale quantization has \n"
- "quantized entry values == 0 (< min)\n");
- exit(1);
- }
- }
- if(c.quantlist[j]<0){
- if(q.log)
- neg=1;
- else{
- fprintf(stderr,"INTERNAL ERROR: Non log scale quantization has \n"
- "quantized entry values < 0 (< min)\n");
- exit(1);
- }
- }
- }
-
-
- /* tie it all together */
-
- fprintf(out,"static encode_aux _vq_aux_%s = {\n",name);
- fprintf(out,"\t_vq_ptr0_%s,\n",name);
- fprintf(out,"\t_vq_ptr1_%s,\n",name);
- fprintf(out,"\t_vq_p_%s,\n",name);
- fprintf(out,"\t_vq_q_%s,\n",name);
- fprintf(out,"\t%ld, %ld\n};\n\n",c.encode_tree->aux,c.encode_tree->aux);
-
- fprintf(out,"static static_codebook _vq_book_%s = {\n",name);
-
- fprintf(out,"\t%ld, %ld, %d, %ld, %ld, %d, %d, %d, %d, %g,\n",
- c.dim,c.entries,q.log,q.min,q.delta,q.quant,q.sequencep,
- zero,neg,q.encodebias);
- fprintf(out,"\t_vq_quantlist_%s,\n",name);
- fprintf(out,"\t_vq_lengthlist_%s,\n",name);
- fprintf(out,"\t&_vq_aux_%s,\n",name);
- fprintf(out,"};\n\n");
- }
+ /* tie it all together */
+
+ fprintf(out,"static encode_aux_nearestmatch _vq_aux_%s = {\n",name);
+ fprintf(out,"\t_vq_ptr0_%s,\n",name);
+ fprintf(out,"\t_vq_ptr1_%s,\n",name);
+ fprintf(out,"\t_vq_p_%s,\n",name);
+ fprintf(out,"\t_vq_q_%s,\n",name);
+ fprintf(out,"\t%ld, %ld\n};\n\n",c.nearest_tree->aux,c.nearest_tree->aux);
+
+ fprintf(out,"static static_codebook _vq_book_%s = {\n",name);
+
+ fprintf(out,"\t%ld, %ld,\n",c.dim,c.entries);
+ fprintf(out,"\t_vq_lengthlist_%s,\n",name);
+ fprintf(out,"\t2, %ld, %ld, %d, %d,\n",
+ q.min,q.delta,q.quant,q.sequencep);
+ fprintf(out,"\t_vq_quantlist_%s,\n",name);
+ fprintf(out,"\t&_vq_aux_%s,\n",name);
+ fprintf(out,"\tNULL\n");
+ fprintf(out,"};\n\n");
+
fprintf(out,"\n#endif\n");
fclose(out);
exit(0);
diff --git a/vq/cascade.c b/vq/cascade.c
index 62904362..85d9c713 100644
--- a/vq/cascade.c
+++ b/vq/cascade.c
@@ -12,7 +12,7 @@
********************************************************************
function: function call to do simple data cascading
- last mod: $Id: cascade.c,v 1.5.4.2 2000/04/06 15:59:38 xiphmont Exp $
+ last mod: $Id: cascade.c,v 1.5.4.3 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
@@ -28,44 +28,37 @@
/* set up metrics */
double count=0.;
-int dim=-1;
-double *work=NULL;
+
void process_preprocess(codebook **bs,char *basename){
- while(*bs){
- codebook *b=*bs;
- if(dim==-1){
- dim=b->c->dim;
- work=malloc(sizeof(double)*dim);
- }else{
- if(dim!=b->c->dim){
- fprintf(stderr,"Each codebook in a cascade must have the same dimensional order\n");
- exit(1);
- }
- }
- bs++;
- }
}
void process_postprocess(codebook **b,char *basename){
fprintf(stderr,"Done. \n");
}
-void process_vector(codebook **bs,double *a){
+void process_vector(codebook **bs,int *addmul,int inter,double *a,int n){
int i;
- memcpy(work,a,dim*sizeof(double));
+ int booknum=0;
while(*bs){
codebook *b=*bs;
- int entry=(b->c->q_log?_logbest(b,a,1):_best(b,a,1));
- double *e=b->valuelist+b->c->dim*entry;
+ int dim=b->dim;
+
+ if(inter){
+ for(i=0;i<n/dim;i++)
+ vorbis_book_besterror(b,a+i,n/dim,addmul[booknum]);
+ }else{
+ for(i=0;i<=n-dim;i+=dim)
+ vorbis_book_besterror(b,a+i,1,addmul[booknum]);
+ }
- for(i=0;i<b->c->dim;i++)work[i]-=e[i];
bs++;
+ booknum++;
}
- for(i=0;i<dim;i++)
- fprintf(stdout,"%f, ",work[i]);
+ for(i=0;i<n;i++)
+ fprintf(stdout,"%f, ",a[i]);
fprintf(stdout,"\n");
if((long)(count++)%100)spinnit("working.... lines: ",count);
@@ -73,7 +66,8 @@ void process_vector(codebook **bs,double *a){
void process_usage(void){
fprintf(stderr,
- "usage: vqcascade book.vqh [book.vqh]... datafile.vqd [datafile.vqd]...\n\n"
+ "usage: vqcascade [-i] +|*<codebook>.vqh [ +|*<codebook.vqh> ]... \n"
+ " datafile.vqd [datafile.vqd]...\n\n"
" data can be taken on stdin. residual error data sent to\n"
" stdout.\n\n");
diff --git a/vq/huffbuild.c b/vq/huffbuild.c
index f9e38d54..6d7cf33a 100644
--- a/vq/huffbuild.c
+++ b/vq/huffbuild.c
@@ -12,7 +12,7 @@
********************************************************************
function: hufftree builder
- last mod: $Id: huffbuild.c,v 1.2.4.1 2000/04/13 04:53:03 xiphmont Exp $
+ last mod: $Id: huffbuild.c,v 1.2.4.2 2000/04/21 16:35:38 xiphmont Exp $
********************************************************************/
@@ -176,10 +176,11 @@ int main(int argc, char *argv[]){
/* the toplevel book */
fprintf(file,"static static_codebook _huff_book_%s = {\n",base);
- fprintf(file,"\t%d, %ld, 0, 0, 0, 0, 0, 0, 0, 0,\n",
- subn,vals);
- fprintf(file,"\tNULL,\n");
+ fprintf(file,"\t%d, %ld,\n",subn,vals);
fprintf(file,"\t_huff_lengthlist_%s,\n",base);
+ fprintf(file,"\t0, 0, 0, 0, 0,\n");
+ fprintf(file,"\tNULL,\n");
+ fprintf(file,"\tNULL,\n");
fprintf(file,"\tNULL,\n");
fprintf(file,"};\n\n");
diff --git a/vq/latticebuild.c b/vq/latticebuild.c
new file mode 100644
index 00000000..65aca502
--- /dev/null
+++ b/vq/latticebuild.c
@@ -0,0 +1,311 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
+ * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
+ * PLEASE READ THESE TERMS DISTRIBUTING. *
+ * *
+ * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
+ * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: utility main for building codebooks from lattice descriptions
+ last mod: $Id: latticebuild.c,v 1.1.2.1 2000/04/21 16:35:40 xiphmont Exp $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include "vorbis/codebook.h"
+#include "../lib/sharedbook.h"
+#include "bookutil.h"
+
+/* The purpose of this util is actually just to count hits and finish
+ packaging the description into a static codebook.
+
+ command line:
+ vqlattice description.vql datafile.vqd
+
+ the lattice description file contains four lines:
+
+ <n> <dim> <multiplicitavep>
+ <value_0> <value_1> <value_2> ... <value_n-1>
+ <thresh_0> <thresh_1> <thresh_2> ... <thresh_n-2>
+ <map_0> <map_1> <map_2> ... <map_n-1>
+
+ vqlattice sends residual data (for the next stage) to stdout, and
+ produces description.vqh */
+
+int main(int argc,char *argv[]){
+ codebook b;
+ static_codebook c;
+ encode_aux_threshmatch t;
+ double *quantlist;
+ long *hits;
+
+ int entries=-1,dim=-1,quantvals=-1,addmul=-1;
+ FILE *out=NULL;
+ FILE *in=NULL;
+ char *line,*name;
+ long j,k;
+
+ memset(&b,0,sizeof(b));
+ memset(&c,0,sizeof(c));
+ memset(&t,0,sizeof(t));
+
+ if(argv[1]==NULL){
+ fprintf(stderr,"Need a lattice description file on the command line.\n");
+ exit(1);
+ }
+
+ {
+ char *ptr;
+ char *filename=calloc(strlen(argv[1])+4,1);
+
+ strcpy(filename,argv[1]);
+ in=fopen(filename,"r");
+ if(!in){
+ fprintf(stderr,"Could not open input file %s\n",filename);
+ exit(1);
+ }
+
+ ptr=strrchr(filename,'.');
+ if(ptr){
+ *ptr='\0';
+ name=strdup(filename);
+ sprintf(ptr,".vqh");
+ }else{
+ name=strdup(filename);
+ strcat(filename,".vqh");
+ }
+
+ out=fopen(filename,"w");
+ if(out==NULL){
+ fprintf(stderr,"Unable to open %s for writing\n",filename);
+ exit(1);
+ }
+ }
+
+ /* read the description */
+ line=get_line(in);
+ if(sscanf(line,"%d %d %d",&quantvals,&dim,&addmul)!=3){
+ fprintf(stderr,"Syntax error reading book file (line 1)\n");
+ exit(1);
+ }
+ entries=pow(quantvals,dim);
+ c.thresh_tree=&t;
+ c.dim=dim;
+ c.entries=entries;
+ c.lengthlist=calloc(entries,sizeof(long));
+ c.maptype=1;
+ c.q_sequencep=0;
+ c.quantlist=calloc(quantvals,sizeof(long));
+ t.quantthresh=calloc(quantvals-1,sizeof(double));
+ t.quantmap=calloc(quantvals,sizeof(int));
+ t.quantvals=quantvals;
+
+ quantlist=malloc(sizeof(long)*c.dim*c.entries);
+ hits=malloc(c.entries*sizeof(long));
+ for(j=0;j<entries;j++)hits[j]=1;
+
+ reset_next_value();
+ setup_line(in);
+ for(j=0;j<quantvals;j++){
+ if(get_line_value(in,quantlist+j)==-1){
+ fprintf(stderr,"Ran out of data on line 2 of description file\n");
+ exit(1);
+ }
+ }
+
+ setup_line(in);
+ for(j=0;j<quantvals-1;j++){
+ if(get_line_value(in,t.quantthresh+j)==-1){
+ fprintf(stderr,"Ran out of data on line 3 of description file\n");
+ exit(1);
+ }
+ }
+
+ setup_line(in);
+ for(j=0;j<quantvals;j++){
+ if(get_next_ivalue(in,t.quantmap+j)==-1){
+ fprintf(stderr,"Ran out of data on line 4 of description file\n");
+ exit(1);
+ }
+ }
+
+ /* gen a real quant list from the more easily human-grokked input */
+ {
+ double min=quantlist[0];
+ double mindel=fabs(quantlist[0]-quantlist[1]);
+ for(j=1;j<quantvals;j++){
+ if(quantlist[j]<min)min=quantlist[j];
+ for(k=0;k<j;k++){
+ double del=fabs(quantlist[j]-quantlist[k]);
+ if(del<mindel)mindel=del;
+ }
+ }
+ c.q_min=_float32_pack(min);
+ c.q_delta=_float32_pack(mindel);
+
+ min=_float32_unpack(c.q_min);
+ mindel=_float32_unpack(c.q_delta);
+ for(j=0;j<quantvals;j++)
+ c.quantlist[j]=rint((quantlist[j]-min)/mindel);
+ }
+
+ vorbis_book_init_encode(&b,&c);
+ fclose(in);
+
+ /* at this point, we have enough to do best entry matching. We
+ don't have counts yet, but that's OK; match, write residual data,
+ and track hits. The build word lengths when we're done */
+
+ /* we have to do our own de-interleave */
+ if(argv[2]==NULL){
+ fprintf(stderr,"Need a data file on the command line.\n");
+ exit(1);
+ }
+ in=fopen(argv[2],"r");
+ if(!in){
+ fprintf(stderr,"Could not open input file %s\n",argv[2]);
+ exit(1);
+ }
+
+ {
+ int cols=0;
+ long lines=0;
+ double *vec;
+ int interleaved;
+ line=setup_line(in);
+ /* count cols before we start reading */
+ {
+ char *temp=line;
+ while(*temp==' ')temp++;
+ for(cols=0;*temp;cols++){
+ while(*temp>32)temp++;
+ while(*temp==' ')temp++;
+ }
+ }
+ vec=alloca(cols*sizeof(double));
+ interleaved=cols/dim;
+
+ while(line){
+ lines++;
+
+ if(!(lines&0xff))spinnit("lines so far...",lines);
+
+ /* don't need to deinterleave; besterror does that for us */
+ for(j=0;j<cols;j++)
+ if(get_line_value(in,vec+j)){
+ fprintf(stderr,"Too few columns on line %ld in data file\n",lines);
+ exit(1);
+ }
+
+ /* process */
+ for(j=0;j<interleaved;j++)
+ hits[vorbis_book_besterror(&b,vec+j,interleaved,addmul)]++;
+
+ /* write */
+ for(j=0;j<cols;j++)
+ fprintf(stdout,"%g, ",vec[j]);
+ fprintf(stdout,"\n");
+
+ line=setup_line(in);
+ }
+ }
+ fclose(in);
+
+ /* build the codeword lengths */
+
+ build_tree_from_lengths(entries,hits,c.lengthlist);
+
+ /* save the book in C header form */
+ fprintf(out,
+ "/********************************************************************\n"
+ " * *\n"
+ " * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *\n"
+ " * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *\n"
+ " * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *\n"
+ " * PLEASE READ THESE TERMS DISTRIBUTING. *\n"
+ " * *\n"
+ " * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-1999 *\n"
+ " * by 1999 Monty <monty@xiph.org> and The XIPHOPHORUS Company *\n"
+ " * http://www.xiph.org/ *\n"
+ " * *\n"
+ " ********************************************************************\n"
+ "\n"
+ " function: static codebook autogenerated by vq/latticebuild\n"
+ "\n"
+ " ********************************************************************/\n\n");
+
+ fprintf(out,"#ifndef _V_%s_VQH_\n#define _V_%s_VQH_\n",name,name);
+ fprintf(out,"#include \"vorbis/codebook.h\"\n\n");
+
+ /* first, the static vectors, then the book structure to tie it together. */
+ /* quantlist */
+ fprintf(out,"static long _vq_quantlist_%s[] = {\n",name);
+ for(j=0;j<_book_maptype1_quantvals(&c);j++){
+ fprintf(out,"\t%ld,\n",c.quantlist[j]);
+ }
+ fprintf(out,"};\n\n");
+
+ /* lengthlist */
+ fprintf(out,"static long _vq_lengthlist_%s[] = {\n",name);
+ for(j=0;j<c.entries;){
+ fprintf(out,"\t");
+ for(k=0;k<16 && j<c.entries;k++,j++)
+ fprintf(out,"%2ld,",c.lengthlist[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ /* quantthresh */
+ fprintf(out,"static double _vq_quantthresh_%s[] = {\n",name);
+ for(j=0;j<t.quantvals-1;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<t.quantvals-1;k++,j++)
+ fprintf(out,"%05g,",t.quantthresh[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ /* quantmap */
+ fprintf(out,"static long _vq_quantmap_%s[] = {\n",name);
+ for(j=0;j<t.quantvals;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<t.quantvals;k++,j++)
+ fprintf(out,"%5ld,",t.quantmap[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ /* tie it all together */
+
+ fprintf(out,"static encode_aux_threshmatch _vq_aux_%s = {\n",name);
+ fprintf(out,"\t_vq_quantthresh_%s,\n",name);
+ fprintf(out,"\t_vq_quantmap_%s,\n",name);
+ fprintf(out,"\t%d\n};\n\n",t.quantvals);
+
+ fprintf(out,"static static_codebook _vq_book_%s = {\n",name);
+
+ fprintf(out,"\t%ld, %ld,\n",c.dim,c.entries);
+ fprintf(out,"\t_vq_lengthlist_%s,\n",name);
+ fprintf(out,"\t2, %ld, %ld, %d, %d,\n",
+ c.q_min,c.q_delta,c.q_quant,c.q_sequencep);
+ fprintf(out,"\t_vq_quantlist_%s,\n",name);
+ fprintf(out,"\tNULL,\n");
+ fprintf(out,"\t&_vq_aux_%s\n",name);
+ fprintf(out,"};\n\n");
+
+ fprintf(out,"\n#endif\n");
+ fclose(out);
+
+ fprintf(stderr,"\r "
+ "\nDone.\n");
+ exit(0);
+}
diff --git a/vq/lspdata.c b/vq/lspdata.c
index 8bb59517..f8e92704 100644
--- a/vq/lspdata.c
+++ b/vq/lspdata.c
@@ -12,7 +12,7 @@
********************************************************************
function: metrics and quantization code for LSP VQ codebooks
- last mod: $Id: lspdata.c,v 1.11.4.2 2000/04/13 04:53:04 xiphmont Exp $
+ last mod: $Id: lspdata.c,v 1.11.4.3 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
@@ -23,7 +23,7 @@
#include "vqext.h"
char *vqext_booktype="LSPdata";
-quant_meta q={0,0,0,1, 0,0}; /* set sequence data */
+quant_meta q={0,0,0,1}; /* set sequence data */
int vqext_aux=1;
void vqext_quantize(vqgen *v,quant_meta *q){
diff --git a/vq/metrics.c b/vq/metrics.c
index 034b139c..90e19ea9 100644
--- a/vq/metrics.c
+++ b/vq/metrics.c
@@ -12,7 +12,7 @@
********************************************************************
function: function calls to collect codebook metrics
- last mod: $Id: metrics.c,v 1.6.4.1 2000/04/06 15:59:38 xiphmont Exp $
+ last mod: $Id: metrics.c,v 1.6.4.2 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
@@ -42,8 +42,7 @@ double *histogram_lo=NULL;
double count=0.;
int books=0;
-int dim=-1;
-double *work;
+int lastdim=-1;
static double *_now(codebook *c, int i){
return c->valuelist+i*c->c->dim;
@@ -59,26 +58,19 @@ int histerrsort(const void *a, const void *b){
void process_preprocess(codebook **bs,char *basename){
while(bs[books]){
codebook *b=bs[books];
- if(dim==-1){
- dim=b->c->dim;
- work=malloc(sizeof(double)*dim);
- }else{
- if(dim!=b->c->dim){
- fprintf(stderr,"Each codebook in a cascade must have the same dimensional order\n");
- exit(1);
- }
- }
+ lastdim=b->c->dim;
books++;
}
+
if(books){
const static_codebook *b=bs[books-1]->c;
histogram=calloc(b->entries,sizeof(double));
histogram_distance=calloc(b->entries,sizeof(double));
- histogram_errorsq=calloc(b->entries*dim,sizeof(double));
- histogram_error=calloc(b->entries*dim,sizeof(double));
- histogram_hi=calloc(b->entries*dim,sizeof(double));
- histogram_lo=calloc(b->entries*dim,sizeof(double));
+ histogram_errorsq=calloc(b->entries*lastdim,sizeof(double));
+ histogram_error=calloc(b->entries*lastdim,sizeof(double));
+ histogram_hi=calloc(b->entries*lastdim,sizeof(double));
+ histogram_lo=calloc(b->entries*lastdim,sizeof(double));
}else{
fprintf(stderr,"Specify at least one codebook\n");
exit(1);
@@ -131,19 +123,19 @@ void process_postprocess(codebook **b,char *basename){
char *buffer=alloca(strlen(basename)+80);
codebook *bb=b[books-1];
- fprintf(stderr,"Done. Processed %ld data points for %ld entries:\n",
- (long)count,bb->c->entries);
+ fprintf(stderr,"Done. Processed %ld data points:\n",
+ (long)count);
fprintf(stderr,"\tglobal mean amplitude: %g\n",
- meanamplitude_acc/(count*dim));
+ meanamplitude_acc/(count*lastdim));
fprintf(stderr,"\tglobal mean squared amplitude: %g\n",
- sqrt(meanamplitudesq_acc/(count*dim)));
+ sqrt(meanamplitudesq_acc/(count*lastdim)));
fprintf(stderr,"\tglobal mean error: %g\n",
- meanerror_acc/(count*dim));
+ meanerror_acc/(count*lastdim));
fprintf(stderr,"\tglobal mean squared error: %g\n",
- sqrt(meanerrorsq_acc/(count*dim)));
+ sqrt(meanerrorsq_acc/(count*lastdim)));
fprintf(stderr,"\tglobal mean deviation: %g\n",
- meandev_acc/(count*dim));
+ meandev_acc/(count*lastdim));
cell_spacing(b);
@@ -224,24 +216,64 @@ void process_postprocess(codebook **b,char *basename){
}
}
-void process_vector(codebook **bs,double *a){
+void process_vector(codebook **bs,int *addmul,int inter,double *a,int n){
int bi;
- int i;
- double amplitude=0.;
- double distance=0.;
+ int i,j;
double base=0.;
- int entry;
- double *e;
- memcpy(work,a,sizeof(double)*dim);
+ double *work=alloca(sizeof(double)*n);
+ double amplitude=0.;
+
+ memcpy(work,a,sizeof(double)*n);
for(bi=0;bi<books;bi++){
codebook *b=bs[bi];
- entry=(b->c->q_log?_logbest(b,work,1):_best(b,work,1));
- e=b->valuelist+b->c->dim*entry;
- for(i=0;i<b->c->dim;i++)work[i]-=e[i];
+ int dim=b->dim;
+
+ if(inter){
+ for(i=0;i<n/dim;i++){
+ int entry=vorbis_book_besterror(b,work+i,n/dim,addmul[bi]);
+
+ if(bi==books-1){
+ double distance=0;
+ histogram[entry]++;
+
+ for(j=0;j<dim;j++){
+ double error=work[i+j*(n/dim)];
+ histogram_errorsq[entry*dim+j]+=error*error;
+ histogram_error[entry*dim+j]+=fabs(error);
+ if(histogram[entry]==0 || histogram_hi[entry*dim+j]<error)
+ histogram_hi[entry*dim+j]=error;
+ if(histogram[entry]==0 || histogram_lo[entry*dim+j]>error)
+ histogram_lo[entry*dim+j]=error;
+ distance+=error*error;
+ }
+ histogram_distance[entry]+=sqrt(distance);
+ }
+ }
+ }else{
+ for(i=0;i<=n-dim;i+=dim){
+ int entry=vorbis_book_besterror(b,work+i,1,addmul[bi]);
+ if(bi==books-1){
+ double distance=0;
+ histogram[entry]++;
+
+ for(j=0;j<dim;j++){
+ double error=work[i+j];
+ histogram_errorsq[entry*dim+j]+=error*error;
+ histogram_error[entry*dim+j]+=fabs(error);
+ if(histogram[entry]==0 || histogram_hi[entry*dim+j]<error)
+ histogram_hi[entry*dim+j]=error;
+ if(histogram[entry]==0 || histogram_lo[entry*dim+j]>error)
+ histogram_lo[entry*dim+j]=error;
+ distance+=error*error;
+ }
+ histogram_distance[entry]+=sqrt(distance);
+ }
+ }
+ }
}
- for(i=0;i<dim;i++){
+ for(i=0;i<n;i++){
double error=work[i];
if(bs[0]->c->q_sequencep){
amplitude=a[i]-base;
@@ -258,25 +290,15 @@ void process_vector(codebook **bs,double *a){
meandev_acc+=fabs(error/amplitude);
else
meandev_acc+=fabs(error); /* yeah, yeah */
-
- histogram_errorsq[entry*dim+i]+=error*error;
- histogram_error[entry*dim+i]+=fabs(error);
- if(histogram[entry]==0 || histogram_hi[entry*dim+i]<error)
- histogram_hi[entry*dim+i]=error;
- if(histogram[entry]==0 || histogram_lo[entry*dim+i]>error)
- histogram_lo[entry*dim+i]=error;
- distance+=error*error;
}
- histogram[entry]++;
- histogram_distance[entry]+=sqrt(distance);
-
if((long)(count++)%100)spinnit("working.... lines: ",count);
}
void process_usage(void){
fprintf(stderr,
- "usage: vqmetrics <codebook>.vqh datafile.vqd [datafile.vqd]...\n\n"
+ "usage: vqmetrics +|*<codebook>.vqh [ +|*<codebook.vqh> ]... \n"
+ " datafile.vqd [datafile.vqd]...\n\n"
" data can be taken on stdin. Output goes to output files:\n"
" basename-me.m: gnuplot: mean error by entry value\n"
" basename-mse.m: gnuplot: mean square error by entry value\n"
diff --git a/vq/partition.c b/vq/partition.c
deleted file mode 100644
index 00c21bdf..00000000
--- a/vq/partition.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/********************************************************************
- * *
- * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
- * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
- * PLEASE READ THESE TERMS DISTRIBUTING. *
- * *
- * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
- * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
- * http://www.xiph.org/ *
- * *
- ********************************************************************
-
- function: function call to do data partitioning
- last mod: $Id: partition.c,v 1.3.4.1 2000/04/06 15:59:38 xiphmont Exp $
-
- ********************************************************************/
-
-/* make n files, one for each cell. partition the input data into the
- N cells */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include "vorbis/codebook.h"
-#include "../lib/sharedbook.h"
-#include "bookutil.h"
-
-/* open all the partitioning files */
-FILE **out;
-long count;
-
-void process_preprocess(codebook **b,char *basename){
- int i;
- char *buffer=alloca(strlen(basename)+80);
- codebook *b0=*b;
-
- if(!b0){
- fprintf(stderr,"Specify at least one codebook, binky.\n");
- exit(1);
- }
- if(b[1]){
- fprintf(stderr,"Ignoring all but first codebook\n");
- exit(1);
- }
-
- out=malloc(sizeof(FILE *)*b0->c->entries);
- for(i=0;i<b0->c->entries;i++){
- sprintf(buffer,"%s-%dp.vqd",basename,i);
- out[i]=fopen(buffer,"w");
- if(out[i]==NULL){
- fprintf(stderr,"Could not open file %s\n",buffer);
- exit(1);
- }
- }
-}
-
-void process_postprocess(codebook **b,char *basename){
- codebook *b0=*b;
- int i;
- for(i=0;i<b0->c->entries;i++)
- fclose(out[i]);
- fprintf(stderr,"Done. \n");
-}
-
-/* just redirect this entry to the appropriate partition file */
-void process_vector(codebook **b,double *a){
- codebook *b0=*b;
- int entry=(b0->c->q_log?_logbest(b0,a,1):_best(b0,a,1));
- int i;
-
- for(i=0;i<b0->c->dim;i++)
- fprintf(out[entry],"%f, ",a[i]);
- fprintf(out[entry],"\n");
- if(count++%100)spinnit("working.... lines: ",count);
-}
-
-void process_usage(void){
- fprintf(stderr,
- "usage: vqpartition codebook.vqh datafile.vqd [datafile.vqd]...\n\n"
- " data can be taken on stdin. partitioning data is written to\n"
-
- " files named <basename>-<n>p.vqh.\n\n");
-
-}
-
-
-
-
diff --git a/vq/residuedata.c b/vq/residuedata.c
index b049b23a..9445c8b0 100644
--- a/vq/residuedata.c
+++ b/vq/residuedata.c
@@ -12,17 +12,10 @@
********************************************************************
function: metrics and quantization code for residue VQ codebooks
- last mod: $Id: residuedata.c,v 1.2.4.3 2000/04/13 04:53:04 xiphmont Exp $
+ last mod: $Id: residuedata.c,v 1.2.4.4 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
-/* note that the codebook abstraction is capable of representing a log
- codebook where there's a negative to positive dB range as well as
- information to indicate negative/positive in the linear domain.
- This trainer isn't that smart; it assumes that incoming data is
- zero (linear) or 0. ... Inf dB, and just offsets 0. dB for purposes
- of quantization */
-
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
@@ -35,7 +28,7 @@
float scalequant=3.;
char *vqext_booktype="RESdata";
-quant_meta q={0,0,0,0, 1,4.}; /* set sequence data */
+quant_meta q={0,0,0,0}; /* set sequence data */
int vqext_aux=0;
static double *quant_save=NULL;
@@ -46,9 +39,7 @@ double *vqext_weight(vqgen *v,double *p){
/* quantize aligned on unit boundaries. Because our grid is likely
very coarse, play 'shuffle the blocks'; don't allow multiple
- entries to fill the same spot as is nearly certain to happen. last
- complication; our scale is log with an offset guarding zero. Don't
- quantize to values in the no-man's land. */
+ entries to fill the same spot as is nearly certain to happen. */
void vqext_quantize(vqgen *v,quant_meta *q){
int j,k;
@@ -63,17 +54,9 @@ void vqext_quantize(vqgen *v,quant_meta *q){
for(j=0;j<n;j++){
for(k=0;k<dim;k++){
double val=_now(v,j)[k];
- double norm=rint((fabs(val)-q->encodebias)/scalequant);
-
- if(norm<0)
- test[k]=0.;
- else{
- if(norm>max)max=norm;
- if(val>0)
- test[k]=norm+1;
- else
- test[k]=-(norm+1);
- }
+ double norm=rint(fabs(val)/scalequant);
+ if(norm>max)max=norm;
+ test[k]=norm;
}
/* allow move only if unoccupied */
@@ -119,20 +102,7 @@ double vqext_metric(vqgen *v,double *e, double *p){
/* We don't interleave here; we assume that the interleave is provided
for us by residuesplit in vorbis/huff/ */
void vqext_addpoint_adj(vqgen *v,double *b,int start,int dim,int cols,int num){
- int i;
- double *buff=alloca(sizeof(double)*dim);
-
- for(i=0;i<dim;i++){
- double val=b[start+i];
- if(val>0.){
- val=todB(val)+q.encodebias;
- }else if(val<0.){
- val=-todB(val)-q.encodebias;
- }
-
- buff[i]=val;
- }
- vqgen_addpoint(v,buff,NULL);
+ vqgen_addpoint(v,b+start,NULL);
}
/* need to reseed because of the coarse quantization we tend to use on
@@ -163,11 +133,7 @@ void vqext_preprocess(vqgen *v){
for(i=0,j=0;i<v->points && j<v->entries;i++){
for(k=0;k<v->elements;k++){
double val=_point(v,i)[k];
- if(val>0.){
- test[k]=rint((val-q.encodebias)/scalequant)*scalequant+q.encodebias;
- }else if(val<0.){
- test[k]=rint((val+q.encodebias)/scalequant)*scalequant-q.encodebias;
- }
+ test[k]=rint(val/scalequant)*scalequant;
}
for(l=0;l<j;l++){
@@ -193,3 +159,4 @@ void vqext_preprocess(vqgen *v){
vqgen_unquantize(v,&q);
}
+
diff --git a/vq/residuesplit.c b/vq/residuesplit.c
index 6c724498..34e25ec1 100644
--- a/vq/residuesplit.c
+++ b/vq/residuesplit.c
@@ -11,8 +11,8 @@
* *
********************************************************************
- function: residue backend 0 partitioner
- last mod: $Id: residuesplit.c,v 1.1.4.1 2000/04/13 04:53:03 xiphmont Exp $
+ function: residue backend 0 partitioner/classifier
+ last mod: $Id: residuesplit.c,v 1.1.4.2 2000/04/21 16:35:38 xiphmont Exp $
********************************************************************/
@@ -20,81 +20,36 @@
#include <string.h>
#include <math.h>
#include <stdio.h>
-#include "../lib/scales.h"
#include "../vq/bookutil.h"
-/* take a masking curve and raw residue; eliminate the inaduble and
- quantize to the final form handed to the VQ. All and any tricks to
- squeeze out bits given knowledge of the encoding mode should go
- here too */
+static FILE *of;
+static FILE **or;
-/* modifies the pcm vector, returns book membership in aux */
+/* currently classify only by maximum amplitude */
/* This is currently a bit specific to/hardwired for mapping 0; things
will need to change in the future when we get real multichannel
mappings */
-/* does not guard against invalid settings; eg, a subn of 16 and a
- subgroup request of 32. Max subn of 128 */
-static void _testhack(double *vec,int n,double *entropy){
- int i,j=0;
- double max=0.;
- double temp[128];
-
- /* setup */
- for(i=0;i<n;i++){
- if(vec[i])
- temp[i]=(todB(vec[i])+6.);
- else
- temp[i]=0.;
- }
-
- /* handle case subgrp==1 outside */
- for(i=0;i<n;i++)
- if(temp[i]>max)max=temp[i];
-
- while(1){
- entropy[j]=max;
- n>>=1;
- j++;
-
- if(n<=0)break;
- for(i=0;i<n;i++){
- temp[i]+=temp[i+n];
- }
- max=0.;
- for(i=0;i<n;i++)
- if(temp[i]>max)max=temp[i];
- }
-}
-
-static FILE *of;
-static FILE **or;
-
-
-/* we evaluate the the entropy measure for each interleaved subgroup */
-int quantaux(double *res,int n,double *bound,int *subgrp,int parts, int subn){
- long i,j,p;
- double entropy[8];
-
+int quantaux(double *res,int n,double *bound,int parts, int subn){
+ long i,j,aux;
+
for(i=0;i<=n-subn;i+=subn){
- int aux;
- int step;
- _testhack(res+i,subn,entropy);
-
+ double max=0.;
+ for(j=0;j<subn;j++)
+ if(fabs(res[i+j])>max)max=fabs(res[i+j]);
+
for(j=0;j<parts-1;j++)
- if(entropy[subgrp[j]]>bound[j])
+ if(max>=bound[j])
break;
aux=j;
-
- fprintf(of,"%d, ",aux);
- step=subn/(1<<subgrp[j]);
-
- for(j=0;j<step;j++){
- for(p=j;p<subn;p+=step)
- fprintf(or[aux],"%g, ",res[p+i]);
- fprintf(or[aux],"\n");
- }
+
+ fprintf(of,"%ld, ",aux);
+
+ for(j=0;j<subn;j++)
+ fprintf(or[aux],"%g, ",res[j+i]);
+
+ fprintf(or[aux],"\n");
}
fprintf(of,"\n");
@@ -127,12 +82,12 @@ static int getline(FILE *in,double *vec,int begin,int n){
static void usage(){
fprintf(stderr,
"usage:\n"
- "residuesplit <res> <begin,n,group> <baseout> <max,subgr> [<max,subgr>]...\n"
+ "residuesplit <res> <begin,n,group> <baseout> <min> [<min>]...\n"
" where begin,n,group is first scalar, \n"
" number of scalars of each in line,\n"
" number of scalars in a group\n"
- " maxent is the maximum allowable entropy heuristic for a group\n"
- "eg: residuesplit mask.vqd floor.vqd 0,1024,16 res 10,2 10,4 5,4 ,8\n"
+ " min is the minimum peak value required for membership in a group\n"
+ "eg: residuesplit mask.vqd floor.vqd 0,1024,16 res 25.5 13.5 7.5 1.5 0\n"
"produces resaux.vqd and res_0...n.vqd\n\n");
exit(1);
}
@@ -140,7 +95,7 @@ static void usage(){
int main(int argc, char *argv[]){
char *buffer;
char *base;
- int i,parts,begin,n,subn,*subgrp;
+ int i,parts,begin,n,subn;
FILE *res;
double *bound,*vec;
long c=0;
@@ -167,23 +122,13 @@ int main(int argc, char *argv[]){
}
/* how many parts?... */
- parts=argc-4;
+ parts=argc-3;
bound=malloc(sizeof(double)*parts);
- subgrp=malloc(sizeof(int)*parts);
-
- for(i=0;i<parts;i++){
- char *pos=strchr(argv[4+i],',');
- if(*argv[4+i]==',')
- bound[i]=1e50;
- else
- bound[i]=atof(argv[4+i]);
- if(!pos){
- subgrp[i]=_ilog(subn)-1;
- }else{
- subgrp[i]=_ilog(atoi(pos+1))-1;
- }
+ for(i=0;i<parts-1;i++){
+ bound[i]=atof(argv[4+i]);
}
+ bound[i]=0;
res=fopen(argv[1],"r");
if(!res){
@@ -211,10 +156,9 @@ int main(int argc, char *argv[]){
/* get the input line by line and process it */
while(!feof(res)){
if(getline(res,vec,begin,n))
- quantaux(vec,n,bound,subgrp,parts,subn);
+ quantaux(vec,n,bound,parts,subn);
c++;
- if(c&0xff==0xff){
- c=0;
+ if(!(c&0xf)){
spinnit("kB so far...",(int)(ftell(res)/1024));
}
}
diff --git a/vq/run.c b/vq/run.c
new file mode 100644
index 00000000..d0fc7339
--- /dev/null
+++ b/vq/run.c
@@ -0,0 +1,218 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
+ * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
+ * PLEASE READ THESE TERMS DISTRIBUTING. *
+ * *
+ * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
+ * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: utility main for loading and operating on codebooks
+ last mod: $Id: run.c,v 1.9.4.1 2000/04/21 16:35:40 xiphmont Exp $
+
+ ********************************************************************/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "bookutil.h"
+
+/* command line:
+ utilname [-i] +|* input_book.vqh [+|* input_book.vqh]
+ input_data.vqd [input_data.vqd]
+
+ produces output data on stdout
+ (may also take input data from stdin)
+
+ */
+
+extern void process_preprocess(codebook **b,char *basename);
+extern void process_postprocess(codebook **b,char *basename);
+extern void process_vector(codebook **b,int *addmul, int inter,double *a,int n);
+extern void process_usage(void);
+
+int main(int argc,char *argv[]){
+ char *basename;
+ codebook **b=calloc(1,sizeof(codebook *));
+ int *addmul=calloc(1,sizeof(int));
+ int books=0;
+ int input=0;
+ int interleave=0;
+ int j;
+ int start=0;
+ int num=-1;
+ argv++;
+
+ if(*argv==NULL){
+ process_usage();
+ exit(1);
+ }
+
+ /* yes, this is evil. However, it's very convenient to parse file
+ extentions */
+
+ while(*argv){
+ if(*argv[0]=='-'){
+ /* option */
+ if(argv[0][1]=='s'){
+ /* subvector */
+ if(sscanf(argv[1],"%d,%d",&start,&num)!=2){
+ num= -1;
+ if(sscanf(argv[1],"%d",&start)!=1){
+ fprintf(stderr,"Syntax error using -s\n");
+ exit(1);
+ }
+ }
+ argv+=2;
+ }
+ if(argv[0][1]=='i'){
+ /* interleave */
+ interleave=1;
+ argv+=1;
+ }
+ }else{
+ /* input file. What kind? */
+ char *dot;
+ char *ext=NULL;
+ char *name=strdup(*argv++);
+ dot=strrchr(name,'.');
+ if(dot)
+ ext=dot+1;
+ else
+ ext="";
+
+ /* codebook */
+ if(!strcmp(ext,"vqh")){
+ int multp=0;
+ if(input){
+ fprintf(stderr,"specify all input data (.vqd) files following\n"
+ "codebook header (.vqh) files\n");
+ exit(1);
+ }
+ /* is it additive or multiplicative? */
+ if(name[0]=='*'){
+ multp=1;
+ name++;
+ }
+ if(name[0]=='+')name++;
+
+ basename=strrchr(name,'/');
+ if(basename)
+ basename=strdup(basename)+1;
+ else
+ basename=strdup(name);
+ dot=strrchr(basename,'.');
+ if(dot)*dot='\0';
+
+ b=realloc(b,sizeof(codebook *)*(books+2));
+ b[books]=codebook_load(name);
+ addmul=realloc(addmul,sizeof(int)*(books+1));
+ addmul[books++]=multp;
+ b[books]=NULL;
+ }
+
+ /* data file */
+ if(!strcmp(ext,"vqd")){
+ int cols;
+ long lines=0;
+ char *line;
+ double *vec;
+ FILE *in=fopen(name,"r");
+ if(!in){
+ fprintf(stderr,"Could not open input file %s\n",name);
+ exit(1);
+ }
+
+ if(!input){
+ process_preprocess(b,basename);
+ input++;
+ }
+
+ reset_next_value();
+ line=get_line(in);
+ /* count cols before we start reading */
+ {
+ char *temp=line;
+ while(*temp==' ')temp++;
+ for(cols=0;*temp;cols++){
+ while(*temp>32)temp++;
+ while(*temp==' ')temp++;
+ }
+ }
+ vec=alloca(cols*sizeof(double));
+ while(line){
+ lines++;
+ for(j=0;j<cols;j++)
+ if(get_line_value(in,vec+j)){
+ fprintf(stderr,"Too few columns on line %ld in data file\n",lines);
+ exit(1);
+ }
+ /* ignores -s for now */
+ process_vector(b,addmul,interleave,vec,cols);
+
+ reset_next_value();
+ line=get_line(in);
+ }
+ fclose(in);
+ }
+ }
+ }
+
+ /* take any data from stdin */
+ {
+ struct stat st;
+ if(fstat(STDIN_FILENO,&st)==-1){
+ fprintf(stderr,"Could not stat STDIN\n");
+ exit(1);
+ }
+ if((S_IFIFO|S_IFREG|S_IFSOCK)&st.st_mode){
+ int cols;
+ char *line;
+ long lines=0;
+ double *vec;
+ if(!input){
+ process_preprocess(b,basename);
+ input++;
+ }
+
+ line=setup_line(stdin);
+ /* count cols before we start reading */
+ {
+ char *temp=line;
+ while(*temp==' ')temp++;
+ for(cols=0;*temp;cols++){
+ while(*temp>32)temp++;
+ while(*temp==' ')temp++;
+ }
+ }
+ vec=alloca(cols*sizeof(double));
+ while(line){
+ lines++;
+ for(j=0;j<cols;j++)
+ if(get_line_value(stdin,vec+j)){
+ fprintf(stderr,"Too few columns on line %ld in data file\n",lines);
+ exit(1);
+ }
+ /* ignores -s for now */
+ process_vector(b,addmul,interleave,vec,cols);
+
+ line=setup_line(stdin);
+ }
+ }
+ }
+
+ process_postprocess(b,basename);
+
+ return 0;
+}
diff --git a/vq/train.c b/vq/train.c
index 75477e04..1ce5d1a1 100644
--- a/vq/train.c
+++ b/vq/train.c
@@ -12,7 +12,7 @@
********************************************************************
function: utility main for training codebooks
- last mod: $Id: train.c,v 1.16.4.3 2000/04/13 04:53:04 xiphmont Exp $
+ last mod: $Id: train.c,v 1.16.4.4 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
@@ -137,8 +137,8 @@ int main(int argc,char *argv[]){
/* quant setup */
line=rline(in,out,1);
- if(sscanf(line,"%d %ld %ld %d %d %lf",&q.log,&q.min,&q.delta,
- &q.quant,&q.sequencep,&q.encodebias)!=6){
+ if(sscanf(line,"%ld %ld %d %d",&q.min,&q.delta,
+ &q.quant,&q.sequencep)!=4){
fprintf(stderr,"Syntax error reading book file\n");
exit(1);
}
@@ -315,8 +315,8 @@ int main(int argc,char *argv[]){
fprintf(out,"# OggVorbis VQ codebook trainer, intermediate file\n");
fprintf(out,"%s\n",vqext_booktype);
fprintf(out,"%d %d %d\n",entries,dim,vqext_aux);
- fprintf(out,"%d %ld %ld %d %d %g\n",
- q.log,q.min,q.delta,q.quant,q.sequencep,q.encodebias);
+ fprintf(out,"%ld %ld %d %d\n",
+ q.min,q.delta,q.quant,q.sequencep);
/* quantized entries */
fprintf(out,"# quantized entries---\n");
diff --git a/vq/vqgen.c b/vq/vqgen.c
index 3c9832de..bef2514f 100644
--- a/vq/vqgen.c
+++ b/vq/vqgen.c
@@ -12,7 +12,7 @@
********************************************************************
function: train a VQ codebook
- last mod: $Id: vqgen.c,v 1.30.4.2 2000/04/06 15:59:38 xiphmont Exp $
+ last mod: $Id: vqgen.c,v 1.30.4.3 2000/04/21 16:35:40 xiphmont Exp $
********************************************************************/
@@ -162,17 +162,8 @@ void vqgen_cellmetric(vqgen *v){
distance between values because each successive value is larger
than the preceeding value. Thus the desired quantibits apply to
the encoded (delta) values, not abs positions. This requires minor
- additional encode-side trickery.
+ additional encode-side trickery. */
- This is mildly complicated by log scales, but less so than in the
- production codebook. Here, the log scaling stays in the log
- domain, but we map 0 linear (which would normally be -Inf log) to 0
- log, and add a fixed offset to 0dB. This allows us to train linear
- data with a positive and negative range on a log scale without
- screwing up the 0 singularity too badly. */
-
-/* This default quantizer doesn't do log quant; a trainer that does
- log quant has to use its own */
void vqgen_quantize(vqgen *v,quant_meta *q){
double maxdel;
@@ -241,12 +232,8 @@ void vqgen_unquantize(vqgen *v,quant_meta *q){
double last=0.;
for(k=0;k<v->elements;k++){
double now=_now(v,j)[k];
- if(now!=0){
- now=(fabs(now)-1.)*delta+last+mindel;
- if(q->sequencep)last=now;
- if(q->log)now+=q->encodebias;
- if(_now(v,j)[k]<0)now= -now;
- }
+ now=fabs(now)*delta+last+mindel;
+ if(q->sequencep)last=now;
_now(v,j)[k]=now;
}
}
diff --git a/vq/vqgen.h b/vq/vqgen.h
index 034d93a2..95c6c2a4 100644
--- a/vq/vqgen.h
+++ b/vq/vqgen.h
@@ -12,7 +12,7 @@
********************************************************************
function: build a VQ codebook
- last mod: $Id: vqgen.h,v 1.12.4.2 2000/04/13 04:53:05 xiphmont Exp $
+ last mod: $Id: vqgen.h,v 1.12.4.3 2000/04/21 16:35:41 xiphmont Exp $
********************************************************************/
@@ -48,9 +48,6 @@ typedef struct {
long delta; /* packed 24 bit float */
int quant; /* 0 < quant <= 16 */
int sequencep; /* bitflag */
-
- int log; /* 0 == linear, 1 == log (dB) mapping */
- double encodebias;
} quant_meta;
static inline double *_point(vqgen *v,long ptr){
diff --git a/vq/vqsplit.c b/vq/vqsplit.c
index 3da0f437..d5d283b8 100644
--- a/vq/vqsplit.c
+++ b/vq/vqsplit.c
@@ -12,7 +12,7 @@
********************************************************************
function: build a VQ codebook and the encoding decision 'tree'
- last mod: $Id: vqsplit.c,v 1.18.4.3 2000/04/13 04:53:05 xiphmont Exp $
+ last mod: $Id: vqsplit.c,v 1.18.4.4 2000/04/21 16:35:41 xiphmont Exp $
********************************************************************/
@@ -150,7 +150,7 @@ int lp_split(vqgen *v,codebook *b,
long *membership,long *reventry,
long depth, long *pointsofar){
- encode_aux *t=b->c->encode_tree;
+ encode_aux_nearestmatch *t=b->c->nearest_tree;
/* The encoder, regardless of book, will be using a straight
euclidian distance-to-point metric to determine closest point.
@@ -336,7 +336,7 @@ int lp_split(vqgen *v,codebook *b,
return(ret);
}
-static int _node_eq(encode_aux *v, long a, long b){
+static int _node_eq(encode_aux_nearestmatch *v, long a, long b){
long Aptr0=v->ptr0[a];
long Aptr1=v->ptr1[a];
long Bptr0=v->ptr0[b];
@@ -355,12 +355,12 @@ static int _node_eq(encode_aux *v, long a, long b){
void vqsp_book(vqgen *v, codebook *b, long *quantlist){
long i,j;
static_codebook *c=(static_codebook *)b->c;
- encode_aux *t;
+ encode_aux_nearestmatch *t;
memset(b,0,sizeof(codebook));
memset(c,0,sizeof(static_codebook));
b->c=c;
- t=c->encode_tree=calloc(1,sizeof(encode_aux));
+ t=c->nearest_tree=calloc(1,sizeof(encode_aux_nearestmatch));
/* make sure there are no duplicate entries and that every
entry has points */