Incremental update... new 100kbps and 128 kbps books
[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 SOURCE IS GOVERNED BY *
5  * THE GNU LESSER/LIBRARY PUBLIC LICENSE, WHICH IS INCLUDED WITH    *
6  * THIS SOURCE. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.        *
7  *                                                                  *
8  * THE OggVorbis 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.18 2000/11/07 09:51:43 xiphmont Exp $
16
17  ********************************************************************/
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <math.h>
23 #include <ogg/ogg.h>
24 #include "vorbis/codec.h"
25 #include "codec_internal.h"
26 #include "codebook.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   vorbis_info_mode *mode;
42   vorbis_info_mapping0 *map;
43
44   vorbis_look_time **time_look;
45   vorbis_look_floor **floor_look;
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   float **decay;
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     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     for(i=0;i<l->map->submaps;i++){
79       l->time_func[i]->free_look(l->time_look[i]);
80       l->floor_func[i]->free_look(l->floor_look[i]);
81       l->residue_func[i]->free_look(l->residue_look[i]);
82       if(l->psy_look)_vp_psy_clear(l->psy_look+i);
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 *mapping0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm,
105                           vorbis_info_mapping *m){
106   int i;
107   vorbis_info          *vi=vd->vi;
108   codec_setup_info     *ci=vi->codec_setup;
109   vorbis_look_mapping0 *look=_ogg_calloc(1,sizeof(vorbis_look_mapping0));
110   vorbis_info_mapping0 *info=look->map=(vorbis_info_mapping0 *)m;
111   look->mode=vm;
112   
113   look->time_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_time *));
114   look->floor_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_floor *));
115
116   look->residue_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_residue *));
117   if(ci->psys)look->psy_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_psy));
118
119   look->time_func=_ogg_calloc(info->submaps,sizeof(vorbis_func_time *));
120   look->floor_func=_ogg_calloc(info->submaps,sizeof(vorbis_func_floor *));
121   look->residue_func=_ogg_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[ci->time_type[timenum]];
129     look->time_look[i]=look->time_func[i]->
130       look(vd,vm,ci->time_param[timenum]);
131     look->floor_func[i]=_floor_P[ci->floor_type[floornum]];
132     look->floor_look[i]=look->floor_func[i]->
133       look(vd,vm,ci->floor_param[floornum]);
134     look->residue_func[i]=_residue_P[ci->residue_type[resnum]];
135     look->residue_look[i]=look->residue_func[i]->
136       look(vd,vm,ci->residue_param[resnum]);
137     
138     if(ci->psys && vd->analysisp){
139       int psynum=info->psysubmap[i];
140       _vp_psy_init(look->psy_look+i,ci->psy_param[psynum],
141                    ci->blocksizes[vm->blockflag]/2,vi->rate);
142     }
143   }
144
145   look->ch=vi->channels;
146   if(ci->psys){
147     look->decay=_ogg_calloc(vi->channels,sizeof(float *));
148     for(i=0;i<vi->channels;i++)
149       look->decay[i]=_ogg_calloc(ci->blocksizes[vm->blockflag]/2,sizeof(float));
150   }
151
152   return(look);
153 }
154
155 static void mapping0_pack(vorbis_info *vi,vorbis_info_mapping *vm,oggpack_buffer *opb){
156   int i;
157   vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)vm;
158
159   oggpack_write(opb,info->submaps-1,4);
160   /* we don't write the channel submappings if we only have one... */
161   if(info->submaps>1){
162     for(i=0;i<vi->channels;i++)
163       oggpack_write(opb,info->chmuxlist[i],4);
164   }
165   for(i=0;i<info->submaps;i++){
166     oggpack_write(opb,info->timesubmap[i],8);
167     oggpack_write(opb,info->floorsubmap[i],8);
168     oggpack_write(opb,info->residuesubmap[i],8);
169   }
170 }
171
172 /* also responsible for range checking */
173 static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){
174   int i;
175   vorbis_info_mapping0 *info=_ogg_calloc(1,sizeof(vorbis_info_mapping0));
176   codec_setup_info     *ci=vi->codec_setup;
177   memset(info,0,sizeof(vorbis_info_mapping0));
178
179   info->submaps=oggpack_read(opb,4)+1;
180
181   if(info->submaps>1){
182     for(i=0;i<vi->channels;i++){
183       info->chmuxlist[i]=oggpack_read(opb,4);
184       if(info->chmuxlist[i]>=info->submaps)goto err_out;
185     }
186   }
187   for(i=0;i<info->submaps;i++){
188     info->timesubmap[i]=oggpack_read(opb,8);
189     if(info->timesubmap[i]>=ci->times)goto err_out;
190     info->floorsubmap[i]=oggpack_read(opb,8);
191     if(info->floorsubmap[i]>=ci->floors)goto err_out;
192     info->residuesubmap[i]=oggpack_read(opb,8);
193     if(info->residuesubmap[i]>=ci->residues)goto err_out;
194   }
195
196   return info;
197
198  err_out:
199   mapping0_free_info(info);
200   return(NULL);
201 }
202
203 #include "os.h"
204 #include "lpc.h"
205 #include "lsp.h"
206 #include "envelope.h"
207 #include "mdct.h"
208 #include "psy.h"
209 #include "scales.h"
210
211 /* no time mapping implementation for now */
212 static long seq=0;
213 static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){
214   vorbis_dsp_state     *vd=vb->vd;
215   vorbis_info          *vi=vd->vi;
216   backend_lookup_state *b=vb->vd->backend_state;
217   vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l;
218   vorbis_info_mapping0 *info=look->map;
219   vorbis_info_mode     *mode=look->mode;
220   int                   n=vb->pcmend;
221   int i,j;
222   float *window=b->window[vb->W][vb->lW][vb->nW][mode->windowtype];
223
224   float **pcmbundle=alloca(sizeof(float *)*vi->channels);
225   int *nonzero=alloca(sizeof(int)*vi->channels);
226  
227   /* time domain pre-window: NONE IMPLEMENTED */
228
229   /* window the PCM data: takes PCM vector, vb; modifies PCM vector */
230
231   for(i=0;i<vi->channels;i++){
232     float *pcm=vb->pcm[i];
233     for(j=0;j<n;j++)
234       pcm[j]*=window[j];
235   }
236             
237   /* time-domain post-window: NONE IMPLEMENTED */
238
239   /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
240   /* only MDCT right now.... */
241   for(i=0;i<vi->channels;i++){
242     float *pcm=vb->pcm[i];
243     mdct_forward(b->transform[vb->W][0],pcm,pcm);
244   }
245
246   {
247     float *floor=_vorbis_block_alloc(vb,n*sizeof(float)/2);
248     
249     for(i=0;i<vi->channels;i++){
250       float *pcm=vb->pcm[i];
251       float *decay=look->decay[i];
252       int submap=info->chmuxlist[i];
253
254       /* if some other mode/mapping was called last frame, our decay
255          accumulator is out of date.  Clear it. */
256       if(look->lastframe+1 != vb->sequence)
257         memset(decay,0,n*sizeof(float)/2);
258
259       /* perform psychoacoustics; do masking */
260       _vp_compute_mask(look->psy_look+submap,pcm,floor,decay);
261  
262       _analysis_output("decay",seq,decay,n/2,0,1);
263       _analysis_output("mdct",seq,pcm,n/2,0,1);
264       _analysis_output("lmdct",seq,pcm,n/2,0,0);
265       _analysis_output("prefloor",seq,floor,n/2,0,1);
266
267       /* perform floor encoding */
268       nonzero[i]=look->floor_func[submap]->
269         forward(vb,look->floor_look[submap],floor,floor);
270
271       _analysis_output("floor",seq,floor,n/2,0,1);
272
273       /* apply the floor, do optional noise levelling */
274       _vp_apply_floor(look->psy_look+submap,pcm,floor);
275       
276       _analysis_output("res",seq++,pcm,n/2,0,0);
277       
278 #ifdef TRAIN_RES
279       if(nonzero[i]){
280         FILE *of;
281         char buffer[80];
282         int i;
283         
284         sprintf(buffer,"residue_%d.vqd",vb->mode);
285         of=fopen(buffer,"a");
286         for(i=0;i<n/2;i++)
287           fprintf(of,"%.2f, ",pcm[i]);
288         fprintf(of,"\n");
289         fclose(of);
290       }
291 #endif      
292
293     }
294     
295     /* perform residue encoding with residue mapping; this is
296        multiplexed.  All the channels belonging to one submap are
297        encoded (values interleaved), then the next submap, etc */
298     
299     for(i=0;i<info->submaps;i++){
300       int ch_in_bundle=0;
301       for(j=0;j<vi->channels;j++){
302         if(info->chmuxlist[j]==i && nonzero[j]==1){
303           pcmbundle[ch_in_bundle++]=vb->pcm[j];
304         }
305       }
306       
307       look->residue_func[i]->forward(vb,look->residue_look[i],
308                                      pcmbundle,ch_in_bundle);
309     }
310   }
311
312   look->lastframe=vb->sequence;
313   return(0);
314 }
315
316 static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){
317   vorbis_dsp_state     *vd=vb->vd;
318   vorbis_info          *vi=vd->vi;
319   codec_setup_info     *ci=vi->codec_setup;
320   backend_lookup_state *b=vd->backend_state;
321   vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l;
322   vorbis_info_mapping0 *info=look->map;
323   vorbis_info_mode     *mode=look->mode;
324   int                   i,j;
325   long                  n=vb->pcmend=ci->blocksizes[vb->W];
326
327   float *window=b->window[vb->W][vb->lW][vb->nW][mode->windowtype];
328   float **pcmbundle=alloca(sizeof(float *)*vi->channels);
329   int *nonzero=alloca(sizeof(int)*vi->channels);
330   
331   /* time domain information decode (note that applying the
332      information would have to happen later; we'll probably add a
333      function entry to the harness for that later */
334   /* NOT IMPLEMENTED */
335
336   /* recover the spectral envelope; store it in the PCM vector for now */
337   for(i=0;i<vi->channels;i++){
338     float *pcm=vb->pcm[i];
339     int submap=info->chmuxlist[i];
340     nonzero[i]=look->floor_func[submap]->
341       inverse(vb,look->floor_look[submap],pcm);
342     _analysis_output("ifloor",seq+i,pcm,n/2,0,1);
343   }
344
345   /* recover the residue, apply directly to the spectral envelope */
346
347   for(i=0;i<info->submaps;i++){
348     int ch_in_bundle=0;
349     for(j=0;j<vi->channels;j++){
350       if(info->chmuxlist[j]==i && nonzero[j])
351         pcmbundle[ch_in_bundle++]=vb->pcm[j];
352     }
353
354     look->residue_func[i]->inverse(vb,look->residue_look[i],pcmbundle,ch_in_bundle);
355   }
356
357   /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
358   /* only MDCT right now.... */
359   for(i=0;i<vi->channels;i++){
360     float *pcm=vb->pcm[i];
361     _analysis_output("out",seq+i,pcm,n/2,0,1);
362     mdct_backward(b->transform[vb->W][0],pcm,pcm);
363   }
364
365   /* now apply the decoded pre-window time information */
366   /* NOT IMPLEMENTED */
367   
368   /* window the data */
369   for(i=0;i<vi->channels;i++){
370     float *pcm=vb->pcm[i];
371     if(nonzero[i])
372       for(j=0;j<n;j++)
373         pcm[j]*=window[j];
374     else
375       for(j=0;j<n;j++)
376         pcm[j]=0.;
377     _analysis_output("final",seq++,pcm,n,0,0);
378   }
379             
380   /* now apply the decoded post-window time information */
381   /* NOT IMPLEMENTED */
382
383   /* all done! */
384   return(0);
385 }
386
387 /* export hooks */
388 vorbis_func_mapping mapping0_exportbundle={
389   &mapping0_pack,&mapping0_unpack,&mapping0_look,&mapping0_copy_info,
390   &mapping0_free_info,&mapping0_free_look,&mapping0_forward,&mapping0_inverse
391 };
392
393
394