res0.c 24.2 KB
Newer Older
Monty's avatar
   
Monty committed
1
2
/********************************************************************
 *                                                                  *
Monty's avatar
   
Monty committed
3
 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
Monty's avatar
   
Monty committed
4
5
6
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
Monty's avatar
   
Monty committed
7
 *                                                                  *
Monty's avatar
   
Monty committed
8
9
 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
 * by the XIPHOPHORUS Company http://www.xiph.org/                  *
Monty's avatar
   
Monty committed
10
 *                                                                  *
Monty's avatar
   
Monty committed
11
12
 ********************************************************************

Monty's avatar
   
Monty committed
13
 function: residue backend 0, 1 and 2 implementation
14
 last mod: $Id: res0.c,v 1.43 2001/12/21 14:52:36 segher Exp $
Monty's avatar
   
Monty committed
15
16
17

 ********************************************************************/

Monty's avatar
   
Monty committed
18
19
20
21
22
/* Slow, slow, slow, simpleminded and did I mention it was slow?  The
   encode/decode loops are coded for clarity and performance is not
   yet even a nagging little idea lurking in the shadows.  Oh and BTW,
   it's slow. */

Monty's avatar
   
Monty committed
23
24
#include <stdlib.h>
#include <string.h>
Monty's avatar
   
Monty committed
25
#include <math.h>
Monty's avatar
   
Monty committed
26
#include <ogg/ogg.h>
Monty's avatar
   
Monty committed
27
#include "vorbis/codec.h"
Monty's avatar
   
Monty committed
28
#include "codec_internal.h"
Monty's avatar
   
Monty committed
29
#include "registry.h"
Monty's avatar
   
Monty committed
30
#include "codebook.h"
Monty's avatar
   
Monty committed
31
#include "misc.h"
Monty's avatar
   
Monty committed
32
#include "os.h"
Monty's avatar
   
Monty committed
33

Monty's avatar
   
Monty committed
34
35
36
37
#ifdef TRAIN_RES
#include <stdio.h>
#endif 

Monty's avatar
   
Monty committed
38
39
typedef struct {
  vorbis_info_residue0 *info;
Monty's avatar
   
Monty committed
40
  int         map;
Monty's avatar
   
Monty committed
41
42
  
  int         parts;
Monty's avatar
   
Monty committed
43
44
  int         stages;
  codebook   *fullbooks;
Monty's avatar
   
Monty committed
45
46
47
48
49
  codebook   *phrasebook;
  codebook ***partbooks;

  int         partvals;
  int       **decodemap;
Monty's avatar
   
Monty committed
50

Monty's avatar
   
Monty committed
51
  long      postbits;
Monty's avatar
   
Monty committed
52
  long      phrasebits;
Monty's avatar
   
Monty committed
53
  long      frames;
Monty's avatar
   
Monty committed
54

Monty's avatar
   
Monty committed
55
56
  int       qoffsets[BITTRACK_DIVISOR+1];

Monty's avatar
   
Monty committed
57
58
#ifdef TRAIN_RES
  long      *training_data[8][64];
Monty's avatar
   
Monty committed
59
60
  float      training_max[8][64];
  float      training_min[8][64];
Monty's avatar
   
Monty committed
61
  int       longp;
Monty's avatar
   
Monty committed
62
63
  float     tmin;
  float     tmax;
Monty's avatar
   
Monty committed
64
65
#endif

Monty's avatar
   
Monty committed
66
} vorbis_look_residue0;
Monty's avatar
   
Monty committed
67

Monty's avatar
   
Monty committed
68
69
vorbis_info_residue *res0_copy_info(vorbis_info_residue *vr){
  vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr;
70
71
  vorbis_info_residue0 *ret=_ogg_malloc(sizeof(*ret));
  memcpy(ret,info,sizeof(*ret));
Monty's avatar
   
Monty committed
72
73
74
  return(ret);
}

Monty's avatar
   
Monty committed
75
void res0_free_info(vorbis_info_residue *i){
76
77
78
79
  vorbis_info_residue0 *info=(vorbis_info_residue0 *)i;
  if(info){
    memset(info,0,sizeof(*info));
    _ogg_free(info);
Monty's avatar
   
Monty committed
80
  }
Monty's avatar
   
Monty committed
81
82
}

Monty's avatar
   
Monty committed
83
void res0_free_look(vorbis_look_residue *i){
Monty's avatar
   
Monty committed
84
  int j;
Monty's avatar
   
Monty committed
85
  if(i){
Monty's avatar
   
Monty committed
86

Monty's avatar
   
Monty committed
87
    vorbis_look_residue0 *look=(vorbis_look_residue0 *)i;
Monty's avatar
   
Monty committed
88

Monty's avatar
   
Monty committed
89
90
91
92
#ifdef TRAIN_RES
    {
      int j,k,l;
      for(j=0;j<look->parts;j++){
Monty's avatar
   
Monty committed
93
	fprintf(stderr,"partition %d: ",j);
Monty's avatar
   
Monty committed
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
	for(k=0;k<8;k++)
	  if(look->training_data[k][j]){
	    char buffer[80];
	    FILE *of;
	    codebook *statebook=look->partbooks[j][k];
	    
	    /* long and short into the same bucket by current convention */
	    sprintf(buffer,"res_part%d_pass%d.vqd",j,k);
	    of=fopen(buffer,"a");

	    for(l=0;l<statebook->entries;l++)
	      fprintf(of,"%d:%ld\n",l,look->training_data[k][j][l]);
	    
	    fclose(of);
	    
Monty's avatar
   
Monty committed
109
110
	    fprintf(stderr,"%d(%.2f|%.2f) ",k,look->training_min[k][j],look->training_max[k][j]);

Monty's avatar
   
Monty committed
111
112
	    _ogg_free(look->training_data[k][j]);
	  }
Monty's avatar
   
Monty committed
113
	fprintf(stderr,"\n");
Monty's avatar
   
Monty committed
114
115
116
117
      }
    }
    fprintf(stderr,"min/max residue: %g::%g\n",look->tmin,look->tmax);

Monty's avatar
   
Monty committed
118
    fprintf(stderr,"residue bit usage %f:%f (%f total)\n",
Monty's avatar
   
Monty committed
119
120
	    (float)look->phrasebits/look->frames,
	    (float)look->postbits/look->frames,
Monty's avatar
   
Monty committed
121
	    (float)(look->postbits+look->phrasebits)/look->frames);
Monty's avatar
   
Monty committed
122
123
#endif

Monty's avatar
   
Monty committed
124
125
126
127

    /*vorbis_info_residue0 *info=look->info;

    fprintf(stderr,
Monty's avatar
   
Monty committed
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
	    "%ld frames encoded in %ld phrasebits and %ld residue bits "
	    "(%g/frame) \n",look->frames,look->phrasebits,
	    look->resbitsflat,
	    (look->phrasebits+look->resbitsflat)/(float)look->frames);
    
    for(j=0;j<look->parts;j++){
      long acc=0;
      fprintf(stderr,"\t[%d] == ",j);
      for(k=0;k<look->stages;k++)
	if((info->secondstages[j]>>k)&1){
	  fprintf(stderr,"%ld,",look->resbits[j][k]);
	  acc+=look->resbits[j][k];
	}

      fprintf(stderr,":: (%ld vals) %1.2fbits/sample\n",look->resvals[j],
	      acc?(float)acc/(look->resvals[j]*info->grouping):0);
    }
    fprintf(stderr,"\n");*/
Monty's avatar
   
Monty committed
146

Monty's avatar
   
Monty committed
147
    for(j=0;j<look->parts;j++)
Monty's avatar
   
Monty committed
148
149
      if(look->partbooks[j])_ogg_free(look->partbooks[j]);
    _ogg_free(look->partbooks);
Monty's avatar
   
Monty committed
150
    for(j=0;j<look->partvals;j++)
Monty's avatar
   
Monty committed
151
152
      _ogg_free(look->decodemap[j]);
    _ogg_free(look->decodemap);
Monty's avatar
   
Monty committed
153

154
155
    memset(look,0,sizeof(*look));
    _ogg_free(look);
Monty's avatar
   
Monty committed
156
  }
Monty's avatar
   
Monty committed
157
158
}

Monty's avatar
   
Monty committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
static int ilog(unsigned int v){
  int ret=0;
  while(v){
    ret++;
    v>>=1;
  }
  return(ret);
}

static int icount(unsigned int v){
  int ret=0;
  while(v){
    ret+=v&1;
    v>>=1;
  }
  return(ret);
}


Monty's avatar
   
Monty committed
178
void res0_pack(vorbis_info_residue *vr,oggpack_buffer *opb){
Monty's avatar
   
Monty committed
179
180
  vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr;
  int j,acc=0;
Monty's avatar
   
Monty committed
181
182
  oggpack_write(opb,info->begin,24);
  oggpack_write(opb,info->end,24);
Monty's avatar
   
Monty committed
183

Monty's avatar
   
Monty committed
184
  oggpack_write(opb,info->grouping-1,24);  /* residue vectors to group and 
Monty's avatar
   
Monty committed
185
					     code with a partitioned book */
Monty's avatar
   
Monty committed
186
187
  oggpack_write(opb,info->partitions-1,6); /* possible partition choices */
  oggpack_write(opb,info->groupbook,8);  /* group huffman book */
Monty's avatar
   
Monty committed
188
189
190
191

  /* secondstages is a bitmask; as encoding progresses pass by pass, a
     bitmask of one indicates this partition class has bits to write
     this pass */
Monty's avatar
   
Monty committed
192
  for(j=0;j<info->partitions;j++){
Monty's avatar
   
Monty committed
193
194
195
196
197
198
199
200
    if(ilog(info->secondstages[j])>3){
      /* yes, this is a minor hack due to not thinking ahead */
      oggpack_write(opb,info->secondstages[j],3); 
      oggpack_write(opb,1,1);
      oggpack_write(opb,info->secondstages[j]>>3,5); 
    }else
      oggpack_write(opb,info->secondstages[j],4); /* trailing zero */
    acc+=icount(info->secondstages[j]);
Monty's avatar
   
Monty committed
201
202
  }
  for(j=0;j<acc;j++)
Monty's avatar
   
Monty committed
203
    oggpack_write(opb,info->booklist[j],8);
Monty's avatar
   
Monty committed
204

Monty's avatar
   
Monty committed
205
206
207
}

/* vorbis_info is for range checking */
Monty's avatar
   
Monty committed
208
vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){
Monty's avatar
   
Monty committed
209
  int j,acc=0;
210
  vorbis_info_residue0 *info=_ogg_calloc(1,sizeof(*info));
Monty's avatar
   
Monty committed
211
  codec_setup_info     *ci=vi->codec_setup;
Monty's avatar
   
Monty committed
212

Monty's avatar
   
Monty committed
213
214
215
216
217
  info->begin=oggpack_read(opb,24);
  info->end=oggpack_read(opb,24);
  info->grouping=oggpack_read(opb,24)+1;
  info->partitions=oggpack_read(opb,6)+1;
  info->groupbook=oggpack_read(opb,8);
Monty's avatar
   
Monty committed
218

Monty's avatar
   
Monty committed
219
  for(j=0;j<info->partitions;j++){
Monty's avatar
   
Monty committed
220
    int cascade=oggpack_read(opb,3);
Monty's avatar
   
Monty committed
221
222
    if(oggpack_read(opb,1))
      cascade|=(oggpack_read(opb,5)<<3);
Monty's avatar
   
Monty committed
223
224
    info->secondstages[j]=cascade;

Monty's avatar
   
Monty committed
225
    acc+=icount(cascade);
Monty's avatar
   
Monty committed
226
  }
Monty's avatar
   
Monty committed
227
  for(j=0;j<acc;j++)
Monty's avatar
   
Monty committed
228
    info->booklist[j]=oggpack_read(opb,8);
Monty's avatar
   
Monty committed
229

Monty's avatar
   
Monty committed
230
  if(info->groupbook>=ci->books)goto errout;
Monty's avatar
   
Monty committed
231
  for(j=0;j<acc;j++)
Monty's avatar
   
Monty committed
232
    if(info->booklist[j]>=ci->books)goto errout;
Monty's avatar
   
Monty committed
233

Monty's avatar
   
Monty committed
234
  return(info);
Monty's avatar
   
Monty committed
235
 errout:
Monty's avatar
   
Monty committed
236
  res0_free_info(info);
Monty's avatar
   
Monty committed
237
  return(NULL);
Monty's avatar
   
Monty committed
238
239
}

Monty's avatar
   
Monty committed
240
vorbis_look_residue *res0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm,
Monty's avatar
   
Monty committed
241
			  vorbis_info_residue *vr){
Monty's avatar
   
Monty committed
242
  vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr;
243
  vorbis_look_residue0 *look=_ogg_calloc(1,sizeof(*look));
Monty's avatar
   
Monty committed
244
245
  backend_lookup_state *be=vd->backend_state;

Monty's avatar
   
Monty committed
246
247
  int j,k,acc=0;
  int dim;
Monty's avatar
   
Monty committed
248
  int maxstage=0;
Monty's avatar
   
Monty committed
249
  look->info=info;
Monty's avatar
   
Monty committed
250
  look->map=vm->mapping;
Monty's avatar
   
Monty committed
251
252

  look->parts=info->partitions;
Monty's avatar
   
Monty committed
253
  look->fullbooks=be->fullbooks;
Monty's avatar
   
Monty committed
254
  look->phrasebook=be->fullbooks+info->groupbook;
Monty's avatar
   
Monty committed
255
256
  dim=look->phrasebook->dim;

257
  look->partbooks=_ogg_calloc(look->parts,sizeof(*look->partbooks));
Monty's avatar
   
Monty committed
258
259

  for(j=0;j<look->parts;j++){
Monty's avatar
   
Monty committed
260
    int stages=ilog(info->secondstages[j]);
Monty's avatar
   
Monty committed
261
    if(stages){
Monty's avatar
   
Monty committed
262
      if(stages>maxstage)maxstage=stages;
263
      look->partbooks[j]=_ogg_calloc(stages,sizeof(*look->partbooks[j]));
Monty's avatar
   
Monty committed
264
      for(k=0;k<stages;k++)
Monty's avatar
   
Monty committed
265
	if(info->secondstages[j]&(1<<k)){
Monty's avatar
   
Monty committed
266
	  look->partbooks[j][k]=be->fullbooks+info->booklist[acc++];
Monty's avatar
   
Monty committed
267
268
269
270
271
#ifdef TRAIN_RES
	  look->training_data[k][j]=calloc(look->partbooks[j][k]->entries,
					   sizeof(***look->training_data));
#endif
	}
Monty's avatar
   
Monty committed
272
273
274
    }
  }

275
  look->partvals=rint(pow((float)look->parts,(pow)dim));
Monty's avatar
   
Monty committed
276
  look->stages=maxstage;
277
  look->decodemap=_ogg_malloc(look->partvals*sizeof(*look->decodemap));
Monty's avatar
   
Monty committed
278
279
280
  for(j=0;j<look->partvals;j++){
    long val=j;
    long mult=look->partvals/look->parts;
281
    look->decodemap[j]=_ogg_malloc(dim*sizeof(*look->decodemap[j]));
Monty's avatar
   
Monty committed
282
283
284
285
286
287
    for(k=0;k<dim;k++){
      long deco=val/mult;
      val-=deco*mult;
      mult/=look->parts;
      look->decodemap[j][k]=deco;
    }
Monty's avatar
   
Monty committed
288
289
  }

Monty's avatar
   
Monty committed
290
291
292
293
294
295
296
297
298
299
300
  {
    int samples_per_partition=info->grouping;
    int n=info->end-info->begin,i;
    int partvals=n/samples_per_partition;

    for(i=0;i<BITTRACK_DIVISOR;i++)
      look->qoffsets[i]=partvals*(i+1)/BITTRACK_DIVISOR;

    look->qoffsets[i]=9999999;
  }

Monty's avatar
   
Monty committed
301
  return(look);
Monty's avatar
   
Monty committed
302
}
Monty's avatar
   
Monty committed
303

Monty's avatar
   
Monty committed
304

305
#if 0
Monty's avatar
   
Monty committed
306
307
/* does not guard against invalid settings; eg, a subn of 16 and a
   subgroup request of 32.  Max subn of 128 */
Monty's avatar
   
Monty committed
308
309
static int _interleaved_testhack(float *vec,int n,vorbis_look_residue0 *look,
				 int auxparts,int auxpartnum){
Monty's avatar
   
Monty committed
310
  vorbis_info_residue0 *info=look->info;
Monty's avatar
   
Monty committed
311
  int i,j=0;
Monty's avatar
   
Monty committed
312
  float max,localmax=0.f;
Monty's avatar
   
Monty committed
313
314
  float temp[128];
  float entropy[8];
Monty's avatar
   
Monty committed
315
316

  /* setup */
Monty's avatar
   
Monty committed
317
  for(i=0;i<n;i++)temp[i]=fabs(vec[i]);
Monty's avatar
   
Monty committed
318
319

  /* handle case subgrp==1 outside */
Monty's avatar
   
Monty committed
320
  for(i=0;i<n;i++)
Monty's avatar
   
Monty committed
321
322
    if(temp[i]>localmax)localmax=temp[i];
  max=localmax;
Monty's avatar
   
Monty committed
323
324

  for(i=0;i<n;i++)temp[i]=rint(temp[i]);
Monty's avatar
   
Monty committed
325
  
Monty's avatar
   
Monty committed
326
327
328
  while(1){
    entropy[j]=localmax;
    n>>=1;
Monty's avatar
   
Monty committed
329
    if(!n)break;
Monty's avatar
   
Monty committed
330
331
332
333
334
    j++;

    for(i=0;i<n;i++){
      temp[i]+=temp[i+n];
    }
Monty's avatar
   
Monty committed
335
    localmax=0.f;
Monty's avatar
   
Monty committed
336
337
338
339
340
    for(i=0;i<n;i++)
      if(temp[i]>localmax)localmax=temp[i];
  }

  for(i=0;i<auxparts-1;i++)
Monty's avatar
   
Monty committed
341
342
    if(auxpartnum<info->blimit[i] &&
       entropy[info->subgrp[i]]<=info->entmax[i] &&
Monty's avatar
   
Monty committed
343
       max<=info->ampmax[i])
Monty's avatar
   
Monty committed
344
      break;
Monty's avatar
   
Monty committed
345

Monty's avatar
   
Monty committed
346
  return(i);
Monty's avatar
   
Monty committed
347
}
348
349
#endif

Monty's avatar
   
Monty committed
350

Monty's avatar
   
Monty committed
351
352
353
static int _testhack(float *vec,int n,vorbis_look_residue0 *look,
		     int auxparts,int auxpartnum){
  vorbis_info_residue0 *info=look->info;
Monty's avatar
   
Monty committed
354
355
  int i;
  float max=0.f;
Monty's avatar
   
Monty committed
356
  float temp[128];
Monty's avatar
   
Monty committed
357
  float entropy=0.f;
Monty's avatar
   
Monty committed
358
359
360
361
362

  /* setup */
  for(i=0;i<n;i++)temp[i]=fabs(vec[i]);

  for(i=0;i<n;i++)
Monty's avatar
   
Monty committed
363
    if(temp[i]>max)max=temp[i];
Monty's avatar
   
Monty committed
364
365

  for(i=0;i<n;i++)temp[i]=rint(temp[i]);
Monty's avatar
   
Monty committed
366
367
368

  for(i=0;i<n;i++)
    entropy+=temp[i];
Monty's avatar
   
Monty committed
369
370
371

  for(i=0;i<auxparts-1;i++)
    if(auxpartnum<info->blimit[i] &&
Monty's avatar
   
Monty committed
372
       entropy<=info->entmax[i] &&
Monty's avatar
   
Monty committed
373
374
375
376
377
378
379
       max<=info->ampmax[i])
      break;

  return(i);
}

static int _interleaved_encodepart(oggpack_buffer *opb,float *vec, int n,
Monty's avatar
   
Monty committed
380
				   codebook *book,long *acc){
Monty's avatar
   
Monty committed
381
382
383
384
385
386
387
  int i,bits=0;
  int dim=book->dim;
  int step=n/dim;

  for(i=0;i<step;i++){
    int entry=vorbis_book_besterror(book,vec+i,step,0);

Monty's avatar
   
Monty committed
388
389
390
391
#ifdef TRAIN_RES
    acc[entry]++;
#endif

Monty's avatar
   
Monty committed
392
    bits+=vorbis_book_encode(book,entry,opb);
Monty's avatar
   
Monty committed
393
  }
Monty's avatar
   
Monty committed
394

Monty's avatar
   
Monty committed
395
396
397
  return(bits);
}
 
Monty's avatar
   
Monty committed
398
static int _encodepart(oggpack_buffer *opb,float *vec, int n,
Monty's avatar
   
Monty committed
399
		       codebook *book,long *acc){
Monty's avatar
   
Monty committed
400
401
402
  int i,bits=0;
  int dim=book->dim;
  int step=n/dim;
Monty's avatar
   
Monty committed
403

Monty's avatar
   
Monty committed
404
405
  for(i=0;i<step;i++){
    int entry=vorbis_book_besterror(book,vec+i*dim,1,0);
Monty's avatar
   
Monty committed
406

Monty's avatar
   
Monty committed
407
408
409
410
#ifdef TRAIN_RES
    acc[entry]++;
#endif

Monty's avatar
   
Monty committed
411
    bits+=vorbis_book_encode(book,entry,opb);
Monty's avatar
   
Monty committed
412
  }
Monty's avatar
   
Monty committed
413
414

  return(bits);
Monty's avatar
   
Monty committed
415
416
}

Monty's avatar
   
Monty committed
417
418
419
420
421
422
423
424
425
426
427
428
429
430
static long **_01class(vorbis_block *vb,vorbis_look_residue *vl,
		       float **in,int ch,
		       int (*classify)(float *,int,vorbis_look_residue0 *,
				       int,int)){
  long i,j;
  vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
  vorbis_info_residue0 *info=look->info;

  /* move all this setup out later */
  int samples_per_partition=info->grouping;
  int possible_partitions=info->partitions;
  int n=info->end-info->begin;

  int partvals=n/samples_per_partition;
431
  long **partword=_vorbis_block_alloc(vb,ch*sizeof(*partword));
Monty's avatar
   
Monty committed
432
433
434
435
436
437

  /* we find the partition type for each partition of each
     channel.  We'll go back and do the interleaved encoding in a
     bit.  For now, clarity */
 
  for(i=0;i<ch;i++){
438
439
    partword[i]=_vorbis_block_alloc(vb,n/samples_per_partition*sizeof(*partword[i]));
    memset(partword[i],0,n/samples_per_partition*sizeof(*partword[i]));
Monty's avatar
   
Monty committed
440
441
442
443
444
445
446
447
448
449
450
451
452
  }

  for(i=0;i<partvals;i++){
    for(j=0;j<ch;j++)
      /* do the partition decision based on the 'entropy'
         int the block */
      partword[j][i]=
	classify(in[j]+i*samples_per_partition+info->begin,
		 samples_per_partition,look,possible_partitions,i);
  
  }

#ifdef TRAIN_RES
Monty's avatar
   
Monty committed
453
  look->longp=vb->W;
Monty's avatar
   
Monty committed
454
455
456
457
458
  {
    FILE *of;
    char buffer[80];
  
    for(i=0;i<ch;i++){
Monty's avatar
   
Monty committed
459
      sprintf(buffer,"resaux_%s.vqd",(vb->mode?"long":"short"));
Monty's avatar
   
Monty committed
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
      of=fopen(buffer,"a");
      for(j=0;j<partvals;j++)
	fprintf(of,"%ld, ",partword[i][j]);
      fprintf(of,"\n");
      fclose(of);
    }
  }
#endif
  look->frames++;

  return(partword);
}

static long **_2class(vorbis_block *vb,vorbis_look_residue *vl,
		       float **in,int ch,
		       int (*classify)(float *,int,vorbis_look_residue0 *,
				       int,int)){
  long i,j,k,l;
  vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
  vorbis_info_residue0 *info=look->info;

  /* move all this setup out later */
  int samples_per_partition=info->grouping;
  int possible_partitions=info->partitions;
  int n=info->end-info->begin;

  int partvals=n/samples_per_partition;
487
488
  long **partword=_vorbis_block_alloc(vb,sizeof(*partword));
  float *work=alloca(sizeof(*work)*samples_per_partition);
Monty's avatar
   
Monty committed
489
490
491
492
493

#ifdef TRAIN_RES
  FILE *of;
  char buffer[80];
#endif
Monty's avatar
   
Monty committed
494
  
495
496
  partword[0]=_vorbis_block_alloc(vb,n*ch/samples_per_partition*sizeof(*partword[0]));
  memset(partword[0],0,n*ch/samples_per_partition*sizeof(*partword[0]));
Monty's avatar
   
Monty committed
497
498
499
500
501
502
503
504
505
506

  for(i=0,j=0,k=0,l=info->begin;i<partvals;i++){
    for(k=0;k<samples_per_partition;k++){
      work[k]=in[j][l];
      j++;
      if(j>=ch){
	j=0;
	l++;
      }
    }
Monty's avatar
   
Monty committed
507

Monty's avatar
   
Monty committed
508
509
    partword[0][i]=
      classify(work,samples_per_partition,look,possible_partitions,i);
Monty's avatar
   
Monty committed
510
511


Monty's avatar
   
Monty committed
512
513
514
  }  

#ifdef TRAIN_RES
Monty's avatar
   
Monty committed
515
  look->longp=vb->W;
Monty's avatar
   
Monty committed
516
517
518
519
520
521
  sprintf(buffer,"resaux_%s.vqd",(vb->mode?"long":"short"));
  of=fopen(buffer,"a");
  for(i=0;i<partvals;i++)
    fprintf(of,"%ld, ",partword[0][i]);
  fprintf(of,"\n");
  fclose(of);
Monty's avatar
   
Monty committed
522
#endif
Monty's avatar
   
Monty committed
523

Monty's avatar
   
Monty committed
524
525
526
527
528
  look->frames++;

  return(partword);
}

Monty's avatar
   
Monty committed
529
530
static int _01forward(vorbis_block *vb,vorbis_look_residue *vl,
		      float **in,int ch,
Monty's avatar
   
Monty committed
531
		      int pass,long **partword,
Monty's avatar
   
Monty committed
532
		      int (*encode)(oggpack_buffer *,float *,int,
Monty's avatar
   
Monty committed
533
				    codebook *,long *),
Monty's avatar
   
Monty committed
534
		      ogg_uint32_t *stats){
Monty's avatar
   
Monty committed
535
  long i,j,k,s;
Monty's avatar
   
Monty committed
536
  vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
Monty's avatar
   
Monty committed
537
  vorbis_info_residue0 *info=look->info;
Monty's avatar
   
Monty committed
538

Monty's avatar
   
Monty committed
539
540
541
542
543
  vorbis_dsp_state      *vd=vb->vd;
  vorbis_info           *vi=vd->vi;
  codec_setup_info      *ci=vi->codec_setup;


Monty's avatar
   
Monty committed
544
545
546
547
548
549
550
  /* move all this setup out later */
  int samples_per_partition=info->grouping;
  int possible_partitions=info->partitions;
  int partitions_per_word=look->phrasebook->dim;
  int n=info->end-info->begin;

  int partvals=n/samples_per_partition;
Monty's avatar
   
Monty committed
551
552
  long resbits[128];
  long resvals[128];
Monty's avatar
   
Monty committed
553

Monty's avatar
   
Monty committed
554
#ifdef TRAIN_RES
Monty's avatar
   
Monty committed
555
556
557
558
  for(i=0;i<ch;i++)
    for(j=info->begin;j<info->end;j++){
      if(in[i][j]>look->tmax)look->tmax=in[i][j];
      if(in[i][j]<look->tmin)look->tmin=in[i][j];
Monty's avatar
   
Monty committed
559
    }
Monty's avatar
   
Monty committed
560
#endif
Monty's avatar
   
Monty committed
561

Monty's avatar
   
Monty committed
562
563
  memset(resbits,0,sizeof(resbits));
  memset(resvals,0,sizeof(resvals));
Monty's avatar
   
Monty committed
564
565
566
  
  /* we code the partition words for each channel, then the residual
     words for a partition per channel until we've written all the
Monty's avatar
   
Monty committed
567
     residual words for that partition word.  Then write the next
Monty's avatar
   
Monty committed
568
     partition channel words... */
Monty's avatar
   
Monty committed
569

Monty's avatar
   
Monty committed
570
571
572
573
574
  for(s=(pass==0?0:ci->passlimit[pass-1]);s<ci->passlimit[pass];s++){
    int bin=0;
    ogg_uint32_t *qptr=NULL;
    if(stats)qptr=stats+s*BITTRACK_DIVISOR;

Monty's avatar
   
Monty committed
575
    for(i=0;i<partvals;){
Monty's avatar
   
Monty committed
576

Monty's avatar
   
Monty committed
577
578
579
      /* first we encode a partition codeword for each channel */
      if(s==0){
	for(j=0;j<ch;j++){
Monty's avatar
   
Monty committed
580
581
582
583
584
585
586
587
588
	  long val=partword[j][i];
	  for(k=1;k<partitions_per_word;k++){
	    val*=possible_partitions;
	    if(i+k<partvals)
	      val+=partword[j][i+k];
	  }	

	  /* training hack */
	  if(val<look->phrasebook->entries)
589
	    look->phrasebits+=vorbis_book_encode(look->phrasebook,val,&vb->opb);
Monty's avatar
   
Monty committed
590
#ifdef TRAIN_RES
Monty's avatar
   
Monty committed
591
592
	  else
	    fprintf(stderr,"!");
Monty's avatar
   
Monty committed
593
#endif
Monty's avatar
   
Monty committed
594
	
Monty's avatar
   
Monty committed
595
	}
Monty's avatar
   
Monty committed
596
      }
Monty's avatar
   
Monty committed
597
      
Monty's avatar
   
Monty committed
598
      /* now we encode interleaved residual values for the partitions */
Monty's avatar
   
Monty committed
599
600
      for(k=0;k<partitions_per_word && i<partvals;k++,i++){
	long offset=i*samples_per_partition+info->begin;
Monty's avatar
   
Monty committed
601
	
Monty's avatar
   
Monty committed
602
603
604
	if(qptr)while(i>=look->qoffsets[bin])
	  qptr[bin++]=oggpack_bits(&vb->opb);

Monty's avatar
   
Monty committed
605
	for(j=0;j<ch;j++){
Monty's avatar
   
Monty committed
606
607
608
	  if(s==0)resvals[partword[j][i]]+=samples_per_partition;
	  if(info->secondstages[partword[j][i]]&(1<<s)){
	    codebook *statebook=look->partbooks[partword[j][i]][s];
Monty's avatar
   
Monty committed
609
	    if(statebook){
Monty's avatar
   
Monty committed
610
611
612
613
614
	      int ret;
	      long *accumulator=NULL;

#ifdef TRAIN_RES
	      accumulator=look->training_data[s][partword[j][i]];
Monty's avatar
   
Monty committed
615
616
617
618
619
620
621
622
623
624
	      {
		int l;
		float *samples=in[j]+offset;
		for(l=0;l<samples_per_partition;l++){
		  if(samples[l]<look->training_min[s][partword[j][i]])
		    look->training_min[s][partword[j][i]]=samples[l];
		  if(samples[l]>look->training_max[s][partword[j][i]])
		    look->training_max[s][partword[j][i]]=samples[l];
		}
	      }
Monty's avatar
   
Monty committed
625
626
627
#endif
	      
	      ret=encode(&vb->opb,in[j]+offset,samples_per_partition,
Monty's avatar
   
Monty committed
628
			 statebook,accumulator);
Monty's avatar
   
Monty committed
629

Monty's avatar
   
Monty committed
630
631
	      look->postbits+=ret;
	      resbits[partword[j][i]]+=ret;
Monty's avatar
   
Monty committed
632
633
634
635
	    }
	  }
	}
      }
Monty's avatar
   
Monty committed
636
637
      if(qptr)while(i>=look->qoffsets[bin])
	qptr[bin++]=oggpack_bits(&vb->opb);
Monty's avatar
   
Monty committed
638
    }
Monty's avatar
   
Monty committed
639
  }
Monty's avatar
   
Monty committed
640

Monty's avatar
   
Monty committed
641
  /*{
Monty's avatar
   
Monty committed
642
643
644
645
646
647
648
    long total=0;
    long totalbits=0;
    fprintf(stderr,"%d :: ",vb->mode);
    for(k=0;k<possible_partitions;k++){
      fprintf(stderr,"%ld/%1.2g, ",resvals[k],(float)resbits[k]/resvals[k]);
      total+=resvals[k];
      totalbits+=resbits[k];
Monty's avatar
   
Monty committed
649
      }
Monty's avatar
   
Monty committed
650
    
Monty's avatar
   
Monty committed
651
    fprintf(stderr,":: %ld:%1.2g\n",total,(double)totalbits/total);
Monty's avatar
   
Monty committed
652
    }*/
Monty's avatar
   
Monty committed
653
  return(0);
Monty's avatar
   
Monty committed
654
}
Monty's avatar
   
Monty committed
655

Monty's avatar
   
Monty committed
656
/* a truncated packet here just means 'stop working'; it's not an error */
Monty's avatar
   
Monty committed
657
658
static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl,
		      float **in,int ch,
Monty's avatar
   
Monty committed
659
		      long (*decodepart)(codebook *, float *, 
Monty's avatar
   
Monty committed
660
					 oggpack_buffer *,int)){
Monty's avatar
   
Monty committed
661

Monty's avatar
   
Monty committed
662
  long i,j,k,l,s;
Monty's avatar
   
Monty committed
663
664
665
666
667
668
669
  vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
  vorbis_info_residue0 *info=look->info;

  /* move all this setup out later */
  int samples_per_partition=info->grouping;
  int partitions_per_word=look->phrasebook->dim;
  int n=info->end-info->begin;
Monty's avatar
   
Monty committed
670
  
Monty's avatar
   
Monty committed
671
672
  int partvals=n/samples_per_partition;
  int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
673
  int ***partword=alloca(ch*sizeof(*partword));
Monty's avatar
   
Monty committed
674

Monty's avatar
   
Monty committed
675
  for(j=0;j<ch;j++)
676
    partword[j]=_vorbis_block_alloc(vb,partwords*sizeof(*partword[j]));
Monty's avatar
   
Monty committed
677
678
679

  for(s=0;s<look->stages;s++){

Monty's avatar
   
Monty committed
680
681
682
    /* each loop decodes on partition codeword containing 
       partitions_pre_word partitions */
    for(i=0,l=0;i<partvals;l++){
Monty's avatar
   
Monty committed
683
684
685
686
687
688
689
690
      if(s==0){
	/* fetch the partition word for each channel */
	for(j=0;j<ch;j++){
	  int temp=vorbis_book_decode(look->phrasebook,&vb->opb);
	  if(temp==-1)goto eopbreak;
	  partword[j][l]=look->decodemap[temp];
	  if(partword[j][l]==NULL)goto errout;
	}
Monty's avatar
   
Monty committed
691
      }
Monty's avatar
   
Monty committed
692
693
      
      /* now we decode residual values for the partitions */
Monty's avatar
   
Monty committed
694
      for(k=0;k<partitions_per_word && i<partvals;k++,i++)
Monty's avatar
   
Monty committed
695
	for(j=0;j<ch;j++){
Monty's avatar
   
Monty committed
696
	  long offset=info->begin+i*samples_per_partition;
Monty's avatar
   
Monty committed
697
698
699
	  if(info->secondstages[partword[j][l][k]]&(1<<s)){
	    codebook *stagebook=look->partbooks[partword[j][l][k]][s];
	    if(stagebook){
Monty's avatar
   
Monty committed
700
	      if(decodepart(stagebook,in[j]+offset,&vb->opb,
Monty's avatar
   
Monty committed
701
			    samples_per_partition)==-1)goto eopbreak;
Monty's avatar
   
Monty committed
702
703
704
705
	    }
	  }
	}
    } 
Monty's avatar
   
Monty committed
706
  }
Monty's avatar
   
Monty committed
707
  
Monty's avatar
   
Monty committed
708
 errout:
Monty's avatar
   
Monty committed
709
 eopbreak:
Monty's avatar
   
Monty committed
710
  return(0);
Monty's avatar
   
Monty committed
711
712
}

Monty's avatar
   
Monty committed
713
714
/* residue 0 and 1 are just slight variants of one another. 0 is
   interleaved, 1 is not */
Monty's avatar
   
Monty committed
715
716
long **res0_class(vorbis_block *vb,vorbis_look_residue *vl,
		  float **in,int *nonzero,int ch){
Monty's avatar
   
Monty committed
717
718
719
720
721
722
  /* we encode only the nonzero parts of a bundle */
  int i,used=0;
  for(i=0;i<ch;i++)
    if(nonzero[i])
      in[used++]=in[i];
  if(used)
Monty's avatar
   
Monty committed
723
724
    /*return(_01class(vb,vl,in,used,_interleaved_testhack));*/
    return(_01class(vb,vl,in,used,_testhack));
Monty's avatar
   
Monty committed
725
726
  else
    return(0);
Monty's avatar
   
Monty committed
727
728
}

Monty's avatar
   
Monty committed
729
730
int res0_forward(vorbis_block *vb,vorbis_look_residue *vl,
		 float **in,float **out,int *nonzero,int ch,
Monty's avatar
   
Monty committed
731
		 int pass, long **partword,ogg_uint32_t *stats){
Monty's avatar
   
Monty committed
732
733
734
735
736
737
738
739
740
741
  /* we encode only the nonzero parts of a bundle */
  int i,j,used=0,n=vb->pcmend/2;
  for(i=0;i<ch;i++)
    if(nonzero[i]){
      for(j=0;j<n;j++)
	out[i][j]+=in[i][j];
      in[used++]=in[i];
    }
  if(used){
    int ret=_01forward(vb,vl,in,used,pass,partword,
Monty's avatar
   
Monty committed
742
		      _interleaved_encodepart,stats);
Monty's avatar
   
Monty committed
743
744
745
746
747
748
749
750
    used=0;
    for(i=0;i<ch;i++)
      if(nonzero[i]){
	for(j=0;j<n;j++)
	  out[i][j]-=in[used][j];
	used++;
      }
    return(ret);
Monty's avatar
   
Monty committed
751
752
753
754
  }else{
    for(i=0;i<vorbis_bitrate_maxmarkers();i++)
      stats[i]=oggpack_bits(&vb->opb);

Monty's avatar
   
Monty committed
755
    return(0);
Monty's avatar
   
Monty committed
756
  }
Monty's avatar
   
Monty committed
757
758
}

Monty's avatar
   
Monty committed
759
760
761
762
763
764
765
766
767
768
int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,
		 float **in,int *nonzero,int ch){
  int i,used=0;
  for(i=0;i<ch;i++)
    if(nonzero[i])
      in[used++]=in[i];
  if(used)
    return(_01inverse(vb,vl,in,used,vorbis_book_decodevs_add));
  else
    return(0);
Monty's avatar
   
Monty committed
769
770
771
}

int res1_forward(vorbis_block *vb,vorbis_look_residue *vl,
Monty's avatar
   
Monty committed
772
		 float **in,float **out,int *nonzero,int ch,
Monty's avatar
   
Monty committed
773
		 int pass, long **partword, ogg_uint32_t *stats){
Monty's avatar
   
Monty committed
774
775
776
777
778
779
780
781
782
  int i,j,used=0,n=vb->pcmend/2;
  for(i=0;i<ch;i++)
    if(nonzero[i]){
      for(j=0;j<n;j++)
	out[i][j]+=in[i][j];
      in[used++]=in[i];
    }

  if(used){
Monty's avatar
   
Monty committed
783
    int ret=_01forward(vb,vl,in,used,pass,partword,_encodepart,stats);
Monty's avatar
   
Monty committed
784
785
786
787
788
789
790
791
    used=0;
    for(i=0;i<ch;i++)
      if(nonzero[i]){
	for(j=0;j<n;j++)
	  out[i][j]-=in[used][j];
	used++;
      }
    return(ret);
Monty's avatar
   
Monty committed
792
793
794
795
  }else{
    for(i=0;i<vorbis_bitrate_maxmarkers();i++)
      stats[i]=oggpack_bits(&vb->opb);

Monty's avatar
   
Monty committed
796
    return(0);
Monty's avatar
   
Monty committed
797
  }
Monty's avatar
   
Monty committed
798
799
800
801
}

long **res1_class(vorbis_block *vb,vorbis_look_residue *vl,
		  float **in,int *nonzero,int ch){
Monty's avatar
   
Monty committed
802
803
804
805
806
  int i,used=0;
  for(i=0;i<ch;i++)
    if(nonzero[i])
      in[used++]=in[i];
  if(used)
Monty's avatar
   
Monty committed
807
    return(_01class(vb,vl,in,used,_testhack));
Monty's avatar
   
Monty committed
808
809
  else
    return(0);
Monty's avatar
   
Monty committed
810
811
}

Monty's avatar
   
Monty committed
812
813
814
815
816
817
818
819
820
821
int res1_inverse(vorbis_block *vb,vorbis_look_residue *vl,
		 float **in,int *nonzero,int ch){
  int i,used=0;
  for(i=0;i<ch;i++)
    if(nonzero[i])
      in[used++]=in[i];
  if(used)
    return(_01inverse(vb,vl,in,used,vorbis_book_decodev_add));
  else
    return(0);
Monty's avatar
   
Monty committed
822
823
}

Monty's avatar
   
Monty committed
824
825
826
827
828
829
830
831
832
833
834
835
long **res2_class(vorbis_block *vb,vorbis_look_residue *vl,
		  float **in,int *nonzero,int ch){
  int i,used=0;
  for(i=0;i<ch;i++)
    if(nonzero[i])
      in[used++]=in[i];
  if(used)
    return(_2class(vb,vl,in,used,_testhack));
  else
    return(0);
}

Monty's avatar
   
Monty committed
836
837
/* res2 is slightly more different; all the channels are interleaved
   into a single vector and encoded. */
Monty's avatar
   
Monty committed
838

Monty's avatar
   
Monty committed
839
int res2_forward(vorbis_block *vb,vorbis_look_residue *vl,
Monty's avatar
   
Monty committed
840
		 float **in,float **out,int *nonzero,int ch,
Monty's avatar
   
Monty committed
841
		 int pass,long **partword,ogg_uint32_t *stats){
Monty's avatar
   
Monty committed
842
  long i,j,k,n=vb->pcmend/2,used=0;
Monty's avatar
   
Monty committed
843
844
845

  /* don't duplicate the code; use a working vector hack for now and
     reshape ourselves into a single channel res1 */
Monty's avatar
   
Monty committed
846
  /* ugly; reallocs for each coupling pass :-( */
847
  float *work=_vorbis_block_alloc(vb,ch*n*sizeof(*work));
Monty's avatar
   
Monty committed
848
  for(i=0;i<ch;i++){
Monty's avatar
   
Monty committed
849
    float *pcm=in[i];
Monty's avatar
   
Monty committed
850
    if(nonzero[i])used++;
Monty's avatar
   
Monty committed
851
852
853
    for(j=0,k=i;j<n;j++,k+=ch)
      work[k]=pcm[j];
  }
Monty's avatar
   
Monty committed
854
  
Monty's avatar
   
Monty committed
855
  if(used){
Monty's avatar
   
Monty committed
856
    int ret=_01forward(vb,vl,&work,1,pass,partword,_encodepart,stats);
Monty's avatar
   
Monty committed
857
858
859
860
861
862
    /* update the sofar vector */
    for(i=0;i<ch;i++){
      float *pcm=in[i];
      float *sofar=out[i];
      for(j=0,k=i;j<n;j++,k+=ch)
	sofar[j]+=pcm[j]-work[k];
Monty's avatar
   
Monty committed
863

Monty's avatar
   
Monty committed
864
865
    }
    return(ret);
Monty's avatar
   
Monty committed
866
867
868
869
  }else{
    for(i=0;i<vorbis_bitrate_maxmarkers();i++)
      stats[i]=oggpack_bits(&vb->opb);

Monty's avatar
   
Monty committed
870
    return(0);
Monty's avatar
   
Monty committed
871
  }
Monty's avatar
   
Monty committed
872
873
874
}

/* duplicate code here as speed is somewhat more important */
Monty's avatar
   
Monty committed
875
876
int res2_inverse(vorbis_block *vb,vorbis_look_residue *vl,
		 float **in,int *nonzero,int ch){
Monty's avatar
   
Monty committed
877
878
879
880
881
882
883
884
885
886
887
  long i,k,l,s;
  vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
  vorbis_info_residue0 *info=look->info;

  /* move all this setup out later */
  int samples_per_partition=info->grouping;
  int partitions_per_word=look->phrasebook->dim;
  int n=info->end-info->begin;

  int partvals=n/samples_per_partition;
  int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
888
  int **partword=_vorbis_block_alloc(vb,partwords*sizeof(*partword));
Monty's avatar
   
Monty committed
889

Monty's avatar
   
Monty committed
890
891
892
  for(i=0;i<ch;i++)if(nonzero[i])break;
  if(i==ch)return(0); /* no nonzero vectors */

Monty's avatar
   
Monty committed
893
  for(s=0;s<look->stages;s++){
Monty's avatar
   
Monty committed
894
    for(i=0,l=0;i<partvals;l++){
Monty's avatar
   
Monty committed
895
896
897
898
899
900
901
902
903
904

      if(s==0){
	/* fetch the partition word */
	int temp=vorbis_book_decode(look->phrasebook,&vb->opb);
	if(temp==-1)goto eopbreak;
	partword[l]=look->decodemap[temp];
	if(partword[l]==NULL)goto errout;
      }

      /* now we decode residual values for the partitions */
Monty's avatar
   
Monty committed
905
      for(k=0;k<partitions_per_word && i<partvals;k++,i++)
Monty's avatar
   
Monty committed
906
907
	if(info->secondstages[partword[l][k]]&(1<<s)){
	  codebook *stagebook=look->partbooks[partword[l][k]][s];
Monty's avatar
   
Monty committed
908
	  
Monty's avatar
   
Monty committed
909
	  if(stagebook){
Monty's avatar
   
Monty committed
910
911
	    if(vorbis_book_decodevv_add(stagebook,in,
					i*samples_per_partition+info->begin,ch,
Monty's avatar
   
Monty committed
912
913
914
915
916
917
918
919
920
921
					&vb->opb,samples_per_partition)==-1)
	      goto eopbreak;
	  }
	}
    } 
  }
  
 errout:
 eopbreak:
  return(0);
Monty's avatar
   
Monty committed
922
923
}

Monty's avatar
   
Monty committed
924

Monty's avatar
   
Monty committed
925
vorbis_func_residue residue0_exportbundle={
Monty's avatar
   
Monty committed
926
927
928
  &res0_pack,
  &res0_unpack,
  &res0_look,
Monty's avatar
   
Monty committed
929
  &res0_copy_info,
Monty's avatar
   
Monty committed
930
931
  &res0_free_info,
  &res0_free_look,
Monty's avatar
   
Monty committed
932
  &res0_class,
Monty's avatar
   
Monty committed
933
934
  &res0_forward,
  &res0_inverse
Monty's avatar
   
Monty committed
935
};
Monty's avatar
   
Monty committed
936
937
938
939
940
941
942
943

vorbis_func_residue residue1_exportbundle={
  &res0_pack,
  &res0_unpack,
  &res0_look,
  &res0_copy_info,
  &res0_free_info,
  &res0_free_look,
Monty's avatar
   
Monty committed
944
  &res1_class,
Monty's avatar
   
Monty committed
945
946
947
  &res1_forward,
  &res1_inverse
};
Monty's avatar
   
Monty committed
948
949
950
951
952
953
954
955

vorbis_func_residue residue2_exportbundle={
  &res0_pack,
  &res0_unpack,
  &res0_look,
  &res0_copy_info,
  &res0_free_info,
  &res0_free_look,
Monty's avatar
   
Monty committed
956
  &res2_class,
Monty's avatar
   
Monty committed
957
958
959
  &res2_forward,
  &res2_inverse
};