Cascading fully functional
[platform/upstream/libvorbis.git] / lib / mapping0.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
7  *                                                                  *
8  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
9  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
10
11  ********************************************************************
12
13  function: channel mapping 0 implementation
14  last mod: $Id: mapping0.c,v 1.29 2001/06/04 05:50:10 xiphmont Exp $
15
16  ********************************************************************/
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <math.h>
22 #include <ogg/ogg.h>
23 #include "vorbis/codec.h"
24 #include "codec_internal.h"
25 #include "codebook.h"
26 #include "bitbuffer.h"
27 #include "registry.h"
28 #include "psy.h"
29 #include "misc.h"
30
31 /* simplistic, wasteful way of doing this (unique lookup for each
32    mode/submapping); there should be a central repository for
33    identical lookups.  That will require minor work, so I'm putting it
34    off as low priority.
35
36    Why a lookup for each backend in a given mode?  Because the
37    blocksize is set by the mode, and low backend lookups may require
38    parameters from other areas of the mode/mapping */
39
40 typedef struct {
41   drft_lookup fft_look;
42   vorbis_info_mode *mode;
43   vorbis_info_mapping0 *map;
44
45   vorbis_look_time **time_look;
46   vorbis_look_floor **floor_look;
47
48   vorbis_look_residue **residue_look;
49   vorbis_look_psy *psy_look;
50
51   vorbis_func_time **time_func;
52   vorbis_func_floor **floor_func;
53   vorbis_func_residue **residue_func;
54
55   int ch;
56   long lastframe; /* if a different mode is called, we need to 
57                      invalidate decay */
58 } vorbis_look_mapping0;
59
60 static vorbis_info_mapping *mapping0_copy_info(vorbis_info_mapping *vm){
61   vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)vm;
62   vorbis_info_mapping0 *ret=_ogg_malloc(sizeof(vorbis_info_mapping0));
63   memcpy(ret,info,sizeof(vorbis_info_mapping0));
64   return(ret);
65 }
66
67 static void mapping0_free_info(vorbis_info_mapping *i){
68   if(i){
69     memset(i,0,sizeof(vorbis_info_mapping0));
70     _ogg_free(i);
71   }
72 }
73
74 static void mapping0_free_look(vorbis_look_mapping *look){
75   int i;
76   vorbis_look_mapping0 *l=(vorbis_look_mapping0 *)look;
77   if(l){
78     drft_clear(&l->fft_look);
79
80     for(i=0;i<l->map->submaps;i++){
81       l->time_func[i]->free_look(l->time_look[i]);
82       l->floor_func[i]->free_look(l->floor_look[i]);
83       l->residue_func[i]->free_look(l->residue_look[i]);
84       if(l->psy_look)_vp_psy_clear(l->psy_look+i);
85     }
86
87     _ogg_free(l->time_func);
88     _ogg_free(l->floor_func);
89     _ogg_free(l->residue_func);
90     _ogg_free(l->time_look);
91     _ogg_free(l->floor_look);
92     _ogg_free(l->residue_look);
93     if(l->psy_look)_ogg_free(l->psy_look);
94     memset(l,0,sizeof(vorbis_look_mapping0));
95     _ogg_free(l);
96   }
97 }
98
99 static vorbis_look_mapping *mapping0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm,
100                           vorbis_info_mapping *m){
101   int i;
102   vorbis_info          *vi=vd->vi;
103   codec_setup_info     *ci=vi->codec_setup;
104   vorbis_look_mapping0 *look=_ogg_calloc(1,sizeof(vorbis_look_mapping0));
105   vorbis_info_mapping0 *info=look->map=(vorbis_info_mapping0 *)m;
106   look->mode=vm;
107   
108   look->time_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_time *));
109   look->floor_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_floor *));
110
111   look->residue_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_residue *));
112   if(ci->psys)look->psy_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_psy));
113
114   look->time_func=_ogg_calloc(info->submaps,sizeof(vorbis_func_time *));
115   look->floor_func=_ogg_calloc(info->submaps,sizeof(vorbis_func_floor *));
116   look->residue_func=_ogg_calloc(info->submaps,sizeof(vorbis_func_residue *));
117   
118   for(i=0;i<info->submaps;i++){
119     int timenum=info->timesubmap[i];
120     int floornum=info->floorsubmap[i];
121     int resnum=info->residuesubmap[i];
122
123     look->time_func[i]=_time_P[ci->time_type[timenum]];
124     look->time_look[i]=look->time_func[i]->
125       look(vd,vm,ci->time_param[timenum]);
126     look->floor_func[i]=_floor_P[ci->floor_type[floornum]];
127     look->floor_look[i]=look->floor_func[i]->
128       look(vd,vm,ci->floor_param[floornum]);
129     look->residue_func[i]=_residue_P[ci->residue_type[resnum]];
130     look->residue_look[i]=look->residue_func[i]->
131       look(vd,vm,ci->residue_param[resnum]);
132     
133     if(ci->psys && vd->analysisp){
134       int psynum=info->psysubmap[i];
135       _vp_psy_init(look->psy_look+i,ci->psy_param[psynum],
136                    ci->blocksizes[vm->blockflag]/2,vi->rate);
137     }
138   }
139
140   look->ch=vi->channels;
141
142   if(vd->analysisp)drft_init(&look->fft_look,ci->blocksizes[vm->blockflag]);
143   return(look);
144 }
145
146 static void mapping0_pack(vorbis_info *vi,vorbis_info_mapping *vm,oggpack_buffer *opb){
147   int i;
148   vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)vm;
149
150   /* leave submaps as a hook to be filled in later */
151   oggpack_write(opb,info->submaps-1,4);
152   /* we don't write the channel submappings if we only have one... */
153   if(info->submaps>1){
154     for(i=0;i<vi->channels;i++)
155       oggpack_write(opb,info->chmuxlist[i],4);
156   }
157   for(i=0;i<info->submaps;i++){
158     oggpack_write(opb,info->timesubmap[i],8);
159     oggpack_write(opb,info->floorsubmap[i],8);
160     oggpack_write(opb,info->residuesubmap[i],8);
161   }
162 }
163
164 /* also responsible for range checking */
165 static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){
166   int i;
167   vorbis_info_mapping0 *info=_ogg_calloc(1,sizeof(vorbis_info_mapping0));
168   codec_setup_info     *ci=vi->codec_setup;
169   memset(info,0,sizeof(vorbis_info_mapping0));
170
171   info->submaps=oggpack_read(opb,4)+1;
172
173   if(info->submaps>1){
174     for(i=0;i<vi->channels;i++){
175       info->chmuxlist[i]=oggpack_read(opb,4);
176       if(info->chmuxlist[i]>=info->submaps)goto err_out;
177     }
178   }
179   for(i=0;i<info->submaps;i++){
180     info->timesubmap[i]=oggpack_read(opb,8);
181     if(info->timesubmap[i]>=ci->times)goto err_out;
182     info->floorsubmap[i]=oggpack_read(opb,8);
183     if(info->floorsubmap[i]>=ci->floors)goto err_out;
184     info->residuesubmap[i]=oggpack_read(opb,8);
185     if(info->residuesubmap[i]>=ci->residues)goto err_out;
186   }
187
188   return info;
189
190  err_out:
191   mapping0_free_info(info);
192   return(NULL);
193 }
194
195 #include "os.h"
196 #include "lpc.h"
197 #include "lsp.h"
198 #include "envelope.h"
199 #include "mdct.h"
200 #include "psy.h"
201 #define VORBIS_IEEE_FLOAT32
202 #include "scales.h"
203
204 /* no time mapping implementation for now */
205 static long seq=0;
206 static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){
207   vorbis_dsp_state      *vd=vb->vd;
208   vorbis_info           *vi=vd->vi;
209   backend_lookup_state  *b=vb->vd->backend_state;
210   vorbis_look_mapping0  *look=(vorbis_look_mapping0 *)l;
211   vorbis_info_mapping0  *info=look->map;
212   vorbis_info_mode      *mode=look->mode;
213   vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal;
214   int                    n=vb->pcmend;
215   int i,j;
216   float *window=b->window[vb->W][vb->lW][vb->nW][mode->windowtype];
217
218   float **pcmbundle=alloca(sizeof(float *)*vi->channels);
219
220   int    *nonzero=alloca(sizeof(int)*vi->channels);
221
222   float *work=_vorbis_block_alloc(vb,n*sizeof(float));
223   float newmax=vbi->ampmax;
224
225   for(i=0;i<vi->channels;i++){
226     float scale=4.f/n;
227     int submap=info->chmuxlist[i];
228     float ret;
229
230     /* the following makes things clearer to *me* anyway */
231     float *pcm     =vb->pcm[i]; 
232     float *mdct    =pcm;
233     float *logmdct =pcm+n/2;
234     float *res     =pcm;
235     float *codedflr=pcm+n/2;
236     float *fft     =work;
237     float *logfft  =work;
238     float *logmax  =work;
239     float *logmask =work+n/2;
240
241     /* window the PCM data */
242     for(j=0;j<n;j++)
243       fft[j]=pcm[j]*=window[j];
244     
245     /* transform the PCM data */
246     /* only MDCT right now.... */
247     mdct_forward(b->transform[vb->W][0],pcm,pcm);
248     for(j=0;j<n/2;j++)
249       logmdct[j]=todB(mdct+j);
250     
251     /* FFT yields more accurate tonal estimation (not phase sensitive) */
252     drft_forward(&look->fft_look,fft);
253     fft[0]*=scale;
254     fft[0]=todB(fft);
255     for(j=1;j<n-1;j+=2){
256       float temp=scale*FAST_HYPOT(fft[j],fft[j+1]);
257       logfft[(j+1)>>1]=todB(&temp);
258     }
259
260     _analysis_output("fft",seq,logfft,n/2,0,0);
261     _analysis_output("mdct",seq,logmdct,n/2,0,0);
262
263     /* perform psychoacoustics; do masking */
264     ret=_vp_compute_mask(look->psy_look+submap,
265                          logfft, /* -> logmax */
266                          logmdct,
267                          logmask,
268                          vbi->ampmax);
269     if(ret>newmax)newmax=ret;
270
271     _analysis_output("mask",seq,logmask,n/2,0,0);
272     
273     /* perform floor encoding */
274     nonzero[i]=look->floor_func[submap]->
275       forward(vb,look->floor_look[submap],
276               mdct,
277               logmdct,
278               logmask,
279               logmax,
280               res,
281               codedflr);
282
283     _analysis_output("codedflr",seq,codedflr,n/2,0,1);
284     _analysis_output("res",seq++,res,n/2,0,0);
285       
286 #ifdef TRAIN_RES
287     if(nonzero[i]){
288       FILE *of;
289       char buffer[80];
290       
291       sprintf(buffer,"residue_%d.vqd",vb->mode);
292       of=fopen(buffer,"a");
293       for(j=0;j<n/2;j++){
294         fprintf(of,"%.2f, ",res[j]);
295         if(fabs(res[j])>1000){
296           fprintf(stderr," %d ",seq-1);
297         }
298       }
299       fprintf(of,"\n");
300       fclose(of);
301     }
302 #endif      
303   }
304
305   vbi->ampmax=newmax;
306
307   /* perform residue encoding with residue mapping; this is
308      multiplexed.  All the channels belonging to one submap are
309      encoded (values interleaved), then the next submap, etc */
310   
311   for(i=0;i<info->submaps;i++){
312     int ch_in_bundle=0;
313     for(j=0;j<vi->channels;j++){
314       if(info->chmuxlist[j]==i && nonzero[j]>0){
315         pcmbundle[ch_in_bundle++]=vb->pcm[j];
316       }
317     }
318     
319     look->residue_func[i]->forward(vb,look->residue_look[i],
320                                    pcmbundle,ch_in_bundle);
321   }
322
323   for(j=0;j<vi->channels;j++){
324     _analysis_output("resres",seq-vi->channels+j,vb->pcm[j],n/2,0,0);
325   }
326   
327   look->lastframe=vb->sequence;
328   return(0);
329 }
330
331 static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){
332   vorbis_dsp_state     *vd=vb->vd;
333   vorbis_info          *vi=vd->vi;
334   codec_setup_info     *ci=vi->codec_setup;
335   backend_lookup_state *b=vd->backend_state;
336   vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l;
337   vorbis_info_mapping0 *info=look->map;
338   vorbis_info_mode     *mode=look->mode;
339   int                   i,j;
340   long                  n=vb->pcmend=ci->blocksizes[vb->W];
341
342   float *window=b->window[vb->W][vb->lW][vb->nW][mode->windowtype];
343   float **pcmbundle=alloca(sizeof(float *)*vi->channels);
344   int *nonzero=alloca(sizeof(int)*vi->channels);
345   
346   /* time domain information decode (note that applying the
347      information would have to happen later; we'll probably add a
348      function entry to the harness for that later */
349   /* NOT IMPLEMENTED */
350
351   /* recover the spectral envelope; store it in the PCM vector for now */
352   for(i=0;i<vi->channels;i++){
353     float *pcm=vb->pcm[i];
354     int submap=info->chmuxlist[i];
355     nonzero[i]=look->floor_func[submap]->
356       inverse(vb,look->floor_look[submap],pcm);
357     _analysis_output("ifloor",seq+i,pcm,n/2,0,1);
358   }
359
360   /* recover the residue, apply directly to the spectral envelope */
361
362   for(i=0;i<info->submaps;i++){
363     int ch_in_bundle=0;
364     for(j=0;j<vi->channels;j++){
365       if(info->chmuxlist[j]==i && nonzero[j])
366         pcmbundle[ch_in_bundle++]=vb->pcm[j];
367     }
368
369     look->residue_func[i]->inverse(vb,look->residue_look[i],pcmbundle,ch_in_bundle);
370   }
371
372   /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
373   /* only MDCT right now.... */
374   for(i=0;i<vi->channels;i++){
375     float *pcm=vb->pcm[i];
376     _analysis_output("out",seq+i,pcm,n/2,0,1);
377     mdct_backward(b->transform[vb->W][0],pcm,pcm);
378   }
379
380   /* now apply the decoded pre-window time information */
381   /* NOT IMPLEMENTED */
382   
383   /* window the data */
384   for(i=0;i<vi->channels;i++){
385     float *pcm=vb->pcm[i];
386     if(nonzero[i])
387       for(j=0;j<n;j++)
388         pcm[j]*=window[j];
389     else
390       for(j=0;j<n;j++)
391         pcm[j]=0.f;
392     _analysis_output("final",seq++,pcm,n,0,0);
393   }
394             
395   /* now apply the decoded post-window time information */
396   /* NOT IMPLEMENTED */
397
398   /* all done! */
399   return(0);
400 }
401
402 /* export hooks */
403 vorbis_func_mapping mapping0_exportbundle={
404   &mapping0_pack,&mapping0_unpack,&mapping0_look,&mapping0_copy_info,
405   &mapping0_free_info,&mapping0_free_look,&mapping0_forward,&mapping0_inverse
406 };
407
408
409