Initial beta 4 merge
[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.23 2001/01/22 01:38:25 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 "bitbuffer.h"
28 #include "registry.h"
29 #include "psy.h"
30 #include "misc.h"
31
32 /* simplistic, wasteful way of doing this (unique lookup for each
33    mode/submapping); there should be a central repository for
34    identical lookups.  That will require minor work, so I'm putting it
35    off as low priority.
36
37    Why a lookup for each backend in a given mode?  Because the
38    blocksize is set by the mode, and low backend lookups may require
39    parameters from other areas of the mode/mapping */
40
41 typedef struct {
42   drft_lookup fft_look;
43   vorbis_info_mode *mode;
44   vorbis_info_mapping0 *map;
45
46   vorbis_look_time **time_look;
47   vorbis_look_floor **floor_look;
48
49   vorbis_look_residue **residue_look;
50   vorbis_look_psy *psy_look;
51
52   vorbis_func_time **time_func;
53   vorbis_func_floor **floor_func;
54   vorbis_func_residue **residue_func;
55
56   int ch;
57   long lastframe; /* if a different mode is called, we need to 
58                      invalidate decay */
59 } vorbis_look_mapping0;
60
61 static vorbis_info_mapping *mapping0_copy_info(vorbis_info_mapping *vm){
62   vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)vm;
63   vorbis_info_mapping0 *ret=_ogg_malloc(sizeof(vorbis_info_mapping0));
64   memcpy(ret,info,sizeof(vorbis_info_mapping0));
65   return(ret);
66 }
67
68 static void mapping0_free_info(vorbis_info_mapping *i){
69   if(i){
70     memset(i,0,sizeof(vorbis_info_mapping0));
71     _ogg_free(i);
72   }
73 }
74
75 static void mapping0_free_look(vorbis_look_mapping *look){
76   int i;
77   vorbis_look_mapping0 *l=(vorbis_look_mapping0 *)look;
78   if(l){
79     drft_clear(&l->fft_look);
80
81     for(i=0;i<l->map->submaps;i++){
82       l->time_func[i]->free_look(l->time_look[i]);
83       l->floor_func[i]->free_look(l->floor_look[i]);
84       l->residue_func[i]->free_look(l->residue_look[i]);
85       if(l->psy_look)_vp_psy_clear(l->psy_look+i);
86     }
87
88     _ogg_free(l->time_func);
89     _ogg_free(l->floor_func);
90     _ogg_free(l->residue_func);
91     _ogg_free(l->time_look);
92     _ogg_free(l->floor_look);
93     _ogg_free(l->residue_look);
94     if(l->psy_look)_ogg_free(l->psy_look);
95     memset(l,0,sizeof(vorbis_look_mapping0));
96     _ogg_free(l);
97   }
98 }
99
100 static vorbis_look_mapping *mapping0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm,
101                           vorbis_info_mapping *m){
102   int i;
103   vorbis_info          *vi=vd->vi;
104   codec_setup_info     *ci=vi->codec_setup;
105   vorbis_look_mapping0 *look=_ogg_calloc(1,sizeof(vorbis_look_mapping0));
106   vorbis_info_mapping0 *info=look->map=(vorbis_info_mapping0 *)m;
107   look->mode=vm;
108   
109   look->time_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_time *));
110   look->floor_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_floor *));
111
112   look->residue_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_residue *));
113   if(ci->psys)look->psy_look=_ogg_calloc(info->submaps,sizeof(vorbis_look_psy));
114
115   look->time_func=_ogg_calloc(info->submaps,sizeof(vorbis_func_time *));
116   look->floor_func=_ogg_calloc(info->submaps,sizeof(vorbis_func_floor *));
117   look->residue_func=_ogg_calloc(info->submaps,sizeof(vorbis_func_residue *));
118   
119   for(i=0;i<info->submaps;i++){
120     int timenum=info->timesubmap[i];
121     int floornum=info->floorsubmap[i];
122     int resnum=info->residuesubmap[i];
123
124     look->time_func[i]=_time_P[ci->time_type[timenum]];
125     look->time_look[i]=look->time_func[i]->
126       look(vd,vm,ci->time_param[timenum]);
127     look->floor_func[i]=_floor_P[ci->floor_type[floornum]];
128     look->floor_look[i]=look->floor_func[i]->
129       look(vd,vm,ci->floor_param[floornum]);
130     look->residue_func[i]=_residue_P[ci->residue_type[resnum]];
131     look->residue_look[i]=look->residue_func[i]->
132       look(vd,vm,ci->residue_param[resnum]);
133     
134     if(ci->psys && vd->analysisp){
135       int psynum=info->psysubmap[i];
136       _vp_psy_init(look->psy_look+i,ci->psy_param[psynum],
137                    ci->blocksizes[vm->blockflag]/2,vi->rate);
138     }
139   }
140
141   look->ch=vi->channels;
142
143   if(vd->analysisp)drft_init(&look->fft_look,ci->blocksizes[vm->blockflag]);
144   return(look);
145 }
146
147 static void mapping0_pack(vorbis_info *vi,vorbis_info_mapping *vm,oggpack_buffer *opb){
148   int i;
149   vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)vm;
150
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 #include "scales.h"
202
203 /* no time mapping implementation for now */
204 static long seq=0;
205 static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){
206   vorbis_dsp_state      *vd=vb->vd;
207   vorbis_info           *vi=vd->vi;
208   backend_lookup_state  *b=vb->vd->backend_state;
209   vorbis_look_mapping0  *look=(vorbis_look_mapping0 *)l;
210   vorbis_info_mapping0  *info=look->map;
211   vorbis_info_mode      *mode=look->mode;
212   vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal;
213   int                    n=vb->pcmend;
214   int i,j;
215   float *window=b->window[vb->W][vb->lW][vb->nW][mode->windowtype];
216
217   float **pcmbundle=alloca(sizeof(float *)*vi->channels);
218
219   int    *nonzero=alloca(sizeof(int)*vi->channels);
220
221   float **floor=_vorbis_block_alloc(vb,vi->channels*sizeof(float *));
222   float *additional=_vorbis_block_alloc(vb,n*sizeof(float));
223   float newmax=vbi->ampmax;
224
225   for(i=0;i<vi->channels;i++){
226     float *pcm=vb->pcm[i];
227     float scale=4.f/n;
228     int submap=info->chmuxlist[i];
229     float ret;
230
231     _analysis_output("pcm",seq,pcm,n,0,0);
232
233     /* window the PCM data */
234     for(j=0;j<n;j++)
235       additional[j]=pcm[j]*=window[j];
236             
237     _analysis_output("windowed",seq,pcm,n,0,0);
238
239     /* transform the PCM data */
240     /* only MDCT right now.... */
241     mdct_forward(b->transform[vb->W][0],pcm,pcm);
242     
243     /* FFT yields more accurate tonal estimation (not phase sensitive) */
244     drft_forward(&look->fft_look,additional);
245     
246     additional[0]*=scale;
247     for(j=1;j<n-1;j+=2)
248       additional[(j+1)>>1]=scale*FAST_HYPOT(additional[j],additional[j+1]);
249
250     /* set up our masking data working vector, and stash unquantized
251        data for later */
252     /*memcpy(pcm+n/2,pcm,n*sizeof(float)/2);*/
253     memcpy(additional+n/2,pcm,n*sizeof(float)/2);
254
255     /* begin masking work */
256     floor[i]=_vorbis_block_alloc(vb,n*sizeof(float)/2);
257
258     //_analysis_output("fft",seq,additional,n/2,0,1);
259     //_analysis_output("mdct",seq,additional+n/2,n/2,0,1);
260     //_analysis_output("lfft",seq,additional,n/2,0,0);
261     //_analysis_output("lmdct",seq,additional+n/2,n/2,0,0);
262
263     /* perform psychoacoustics; do masking */
264     ret=_vp_compute_mask(look->psy_look+submap,additional,additional+n/2,
265                          floor[i],NULL,vbi->ampmax);
266     if(ret>newmax)newmax=ret;
267
268     _analysis_output("prefloor",seq,floor[i],n/2,0,0);
269     
270     /* perform floor encoding */
271     nonzero[i]=look->floor_func[submap]->
272       forward(vb,look->floor_look[submap],floor[i]);
273
274     _analysis_output("floor",seq,floor[i],n/2,0,1);
275
276     /* apply the floor, do optional noise levelling */
277     _vp_apply_floor(look->psy_look+submap,pcm,floor[i]);
278
279     _analysis_output("res",seq++,pcm,n/2,0,0);
280       
281 #ifdef TRAIN_RES
282     if(nonzero[i]){
283       FILE *of;
284       char buffer[80];
285       int i;
286       
287       sprintf(buffer,"residue_%d.vqd",vb->mode);
288       of=fopen(buffer,"a");
289       for(i=0;i<n/2;i++)
290         fprintf(of,"%.2f, ",pcm[i]);
291       fprintf(of,"\n");
292       fclose(of);
293     }
294 #endif      
295     
296   }
297
298   vbi->ampmax=newmax;
299
300   /* perform residue encoding with residue mapping; this is
301      multiplexed.  All the channels belonging to one submap are
302      encoded (values interleaved), then the next submap, etc */
303   
304   for(i=0;i<info->submaps;i++){
305     int ch_in_bundle=0;
306     for(j=0;j<vi->channels;j++){
307       if(info->chmuxlist[j]==i && nonzero[j]>0){
308         pcmbundle[ch_in_bundle++]=vb->pcm[j];
309       }
310     }
311     
312     look->residue_func[i]->forward(vb,look->residue_look[i],
313                                    pcmbundle,ch_in_bundle);
314   }
315   
316   look->lastframe=vb->sequence;
317   return(0);
318 }
319
320 static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){
321   vorbis_dsp_state     *vd=vb->vd;
322   vorbis_info          *vi=vd->vi;
323   codec_setup_info     *ci=vi->codec_setup;
324   backend_lookup_state *b=vd->backend_state;
325   vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l;
326   vorbis_info_mapping0 *info=look->map;
327   vorbis_info_mode     *mode=look->mode;
328   int                   i,j;
329   long                  n=vb->pcmend=ci->blocksizes[vb->W];
330
331   float *window=b->window[vb->W][vb->lW][vb->nW][mode->windowtype];
332   float **pcmbundle=alloca(sizeof(float *)*vi->channels);
333   int *nonzero=alloca(sizeof(int)*vi->channels);
334   
335   /* time domain information decode (note that applying the
336      information would have to happen later; we'll probably add a
337      function entry to the harness for that later */
338   /* NOT IMPLEMENTED */
339
340   /* recover the spectral envelope; store it in the PCM vector for now */
341   for(i=0;i<vi->channels;i++){
342     float *pcm=vb->pcm[i];
343     int submap=info->chmuxlist[i];
344     nonzero[i]=look->floor_func[submap]->
345       inverse(vb,look->floor_look[submap],pcm);
346     _analysis_output("ifloor",seq+i,pcm,n/2,0,1);
347   }
348
349   /* recover the residue, apply directly to the spectral envelope */
350
351   for(i=0;i<info->submaps;i++){
352     int ch_in_bundle=0;
353     for(j=0;j<vi->channels;j++){
354       if(info->chmuxlist[j]==i && nonzero[j])
355         pcmbundle[ch_in_bundle++]=vb->pcm[j];
356     }
357
358     look->residue_func[i]->inverse(vb,look->residue_look[i],pcmbundle,ch_in_bundle);
359   }
360
361   /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
362   /* only MDCT right now.... */
363   for(i=0;i<vi->channels;i++){
364     float *pcm=vb->pcm[i];
365     _analysis_output("out",seq+i,pcm,n/2,0,1);
366     mdct_backward(b->transform[vb->W][0],pcm,pcm);
367   }
368
369   /* now apply the decoded pre-window time information */
370   /* NOT IMPLEMENTED */
371   
372   /* window the data */
373   for(i=0;i<vi->channels;i++){
374     float *pcm=vb->pcm[i];
375     if(nonzero[i])
376       for(j=0;j<n;j++)
377         pcm[j]*=window[j];
378     else
379       for(j=0;j<n;j++)
380         pcm[j]=0.f;
381     _analysis_output("final",seq++,pcm,n,0,0);
382   }
383             
384   /* now apply the decoded post-window time information */
385   /* NOT IMPLEMENTED */
386
387   /* all done! */
388   return(0);
389 }
390
391 /* export hooks */
392 vorbis_func_mapping mapping0_exportbundle={
393   &mapping0_pack,&mapping0_unpack,&mapping0_look,&mapping0_copy_info,
394   &mapping0_free_info,&mapping0_free_look,&mapping0_forward,&mapping0_inverse
395 };
396
397
398