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