2a29337d24b1dd90111abc182fcbd94a059f1f91
[opus.git] / libcelt / celt.c
1 /* (C) 2007 Jean-Marc Valin, CSIRO
2 */
3 /*
4    Redistribution and use in source and binary forms, with or without
5    modification, are permitted provided that the following conditions
6    are met:
7    
8    - Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10    
11    - Redistributions in binary form must reproduce the above copyright
12    notice, this list of conditions and the following disclaimer in the
13    documentation and/or other materials provided with the distribution.
14    
15    - Neither the name of the Xiph.org Foundation nor the names of its
16    contributors may be used to endorse or promote products derived from
17    this software without specific prior written permission.
18    
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include "os_support.h"
37 #include "mdct.h"
38 #include <math.h>
39 #include "celt.h"
40 #include "pitch.h"
41 #include "kiss_fftr.h"
42 #include "bands.h"
43 #include "modes.h"
44 #include "entcode.h"
45 #include "quant_pitch.h"
46 #include "quant_bands.h"
47 #include "psy.h"
48 #include "rate.h"
49
50 #define MAX_PERIOD 1024
51
52 #ifndef M_PI
53 #define M_PI 3.14159263
54 #endif
55
56 /** Encoder state 
57  @brief Encoder state
58  */
59 struct CELTEncoder {
60    const CELTMode *mode;     /**< Mode used by the encoder */
61    int frame_size;
62    int block_size;
63    int nb_blocks;
64    int overlap;
65    int channels;
66    
67    ec_byte_buffer buf;
68    ec_enc         enc;
69
70    float preemph;
71    float *preemph_memE;
72    float *preemph_memD;
73    
74    mdct_lookup mdct_lookup;
75    kiss_fftr_cfg fft;
76    struct PsyDecay psy;
77    
78    float *window;
79    float *in_mem;
80    float *mdct_overlap;
81    float *out_mem;
82
83    float *oldBandE;
84 };
85
86
87
88 CELTEncoder *celt_encoder_create(const CELTMode *mode)
89 {
90    int i, N, B, C, N4;
91    CELTEncoder *st;
92    N = mode->mdctSize;
93    B = mode->nbMdctBlocks;
94    C = mode->nbChannels;
95    st = celt_alloc(sizeof(CELTEncoder));
96    
97    st->mode = mode;
98    st->frame_size = B*N;
99    st->block_size = N;
100    st->nb_blocks  = B;
101    st->overlap = mode->overlap;
102
103    N4 = (N-st->overlap)/2;
104    ec_byte_writeinit(&st->buf);
105    ec_enc_init(&st->enc,&st->buf);
106
107    mdct_init(&st->mdct_lookup, 2*N);
108    st->fft = kiss_fftr_alloc(MAX_PERIOD*C, 0, 0);
109    psydecay_init(&st->psy, MAX_PERIOD*C/2, st->mode->Fs);
110    
111    st->window = celt_alloc(2*N*sizeof(float));
112    st->in_mem = celt_alloc(N*C*sizeof(float));
113    st->mdct_overlap = celt_alloc(N*C*sizeof(float));
114    st->out_mem = celt_alloc(MAX_PERIOD*C*sizeof(float));
115    for (i=0;i<2*N;i++)
116       st->window[i] = 0;
117    for (i=0;i<st->overlap;i++)
118       st->window[N4+i] = st->window[2*N-N4-i-1] 
119             = sin(.5*M_PI* sin(.5*M_PI*(i+.5)/st->overlap) * sin(.5*M_PI*(i+.5)/st->overlap));
120    for (i=0;i<2*N4;i++)
121       st->window[N-N4+i] = 1;
122    st->oldBandE = celt_alloc(C*mode->nbEBands*sizeof(float));
123
124    st->preemph = 0.8;
125    st->preemph_memE = celt_alloc(C*sizeof(float));;
126    st->preemph_memD = celt_alloc(C*sizeof(float));;
127
128    return st;
129 }
130
131 void celt_encoder_destroy(CELTEncoder *st)
132 {
133    if (st == NULL)
134    {
135       celt_warning("NULL passed to celt_encoder_destroy");
136       return;
137    }
138    ec_byte_writeclear(&st->buf);
139
140    mdct_clear(&st->mdct_lookup);
141    kiss_fft_free(st->fft);
142    psydecay_clear(&st->psy);
143
144    celt_free(st->window);
145    celt_free(st->in_mem);
146    celt_free(st->mdct_overlap);
147    celt_free(st->out_mem);
148    
149    celt_free(st->oldBandE);
150    
151    celt_free(st->preemph_memE);
152    celt_free(st->preemph_memD);
153    
154    celt_free(st);
155 }
156
157
158 static float compute_mdcts(mdct_lookup *mdct_lookup, float *window, float *in, float *out, int N, int B, int C)
159 {
160    int i, c;
161    float E = 1e-15;
162    VARDECL(float *x);
163    VARDECL(float *tmp);
164    ALLOC(x, 2*N, float);
165    ALLOC(tmp, N, float);
166    for (c=0;c<C;c++)
167    {
168       for (i=0;i<B;i++)
169       {
170          int j;
171          for (j=0;j<2*N;j++)
172          {
173             x[j] = window[j]*in[C*i*N+C*j+c];
174             E += x[j]*x[j];
175          }
176          mdct_forward(mdct_lookup, x, tmp);
177          /* Interleaving the sub-frames */
178          for (j=0;j<N;j++)
179             out[C*B*j+C*i+c] = tmp[j];
180       }
181    }
182    return E;
183 }
184
185 static void compute_inv_mdcts(mdct_lookup *mdct_lookup, float *window, float *X, float *out_mem, float *mdct_overlap, int N, int overlap, int B, int C)
186 {
187    int i, c, N4;
188    VARDECL(float *x);
189    VARDECL(float *tmp);
190    ALLOC(x, 2*N, float);
191    ALLOC(tmp, N, float);
192    N4 = (N-overlap)/2;
193    for (c=0;c<C;c++)
194    {
195       for (i=0;i<B;i++)
196       {
197          int j;
198          /* De-interleaving the sub-frames */
199          for (j=0;j<N;j++)
200             tmp[j] = X[C*B*j+C*i+c];
201          mdct_backward(mdct_lookup, tmp, x);
202          for (j=0;j<2*N;j++)
203             x[j] = window[j]*x[j];
204          for (j=0;j<overlap;j++)
205             out_mem[C*(MAX_PERIOD+(i-B)*N)+C*j+c] = x[N4+j]+mdct_overlap[C*j+c];
206          for (j=0;j<2*N4;j++)
207             out_mem[C*(MAX_PERIOD+(i-B)*N)+C*(j+overlap)+c] = x[j+N4+overlap];
208          for (j=0;j<overlap;j++)
209             mdct_overlap[C*j+c] = x[N+N4+j];
210       }
211    }
212 }
213
214 int celt_encode(CELTEncoder *st, celt_int16_t *pcm, unsigned char *compressed, int nbCompressedBytes)
215 {
216    int i, c, N, B, C, N4;
217    int has_pitch;
218    int pitch_index;
219    float curr_power, pitch_power;
220    VARDECL(float *in);
221    VARDECL(float *X);
222    VARDECL(float *P);
223    VARDECL(float *mask);
224    VARDECL(float *bandE);
225    VARDECL(float *gains);
226    N = st->block_size;
227    B = st->nb_blocks;
228    C = st->mode->nbChannels;
229    ALLOC(in, (B+1)*C*N, float);
230    ALLOC(X, B*C*N, float);         /**< Interleaved signal MDCTs */
231    ALLOC(P, B*C*N, float);         /**< Interleaved pitch MDCTs*/
232    ALLOC(mask, B*C*N, float);      /**< Masking curve */
233    ALLOC(bandE,st->mode->nbEBands*C, float);
234    ALLOC(gains,st->mode->nbPBands, float);
235    
236    N4 = (N-st->overlap)/2;
237
238    for (c=0;c<C;c++)
239    {
240       for (i=0;i<N4;i++)
241          in[C*i+c] = 0;
242       for (i=0;i<st->overlap;i++)
243          in[C*(i+N4)+c] = st->in_mem[C*i+c];
244       for (i=0;i<B*N;i++)
245       {
246          float tmp = pcm[C*i+c];
247          in[C*(i+st->overlap+N4)+c] = tmp - st->preemph*st->preemph_memE[c];
248          st->preemph_memE[c] = tmp;
249       }
250       for (i=N*(B+1)-N4;i<N*(B+1);i++)
251          in[C*i+c] = 0;
252       for (i=0;i<st->overlap;i++)
253          st->in_mem[C*i+c] = in[C*(N*(B+1)-N4-st->overlap+i)+c];
254    }
255    /*for (i=0;i<(B+1)*C*N;i++) printf ("%f(%d) ", in[i], i); printf ("\n");*/
256    /* Compute MDCTs */
257    curr_power = compute_mdcts(&st->mdct_lookup, st->window, in, X, N, B, C);
258
259 #if 0 /* Mask disabled until it can be made to do something useful */
260    compute_mdct_masking(X, mask, B*C*N, st->Fs);
261
262    /* Invert and stretch the mask to length of X 
263       For some reason, I get better results by using the sqrt instead,
264       although there's no valid reason to. Must investigate further */
265    for (i=0;i<B*C*N;i++)
266       mask[i] = 1/(.1+mask[i]);
267 #else
268    for (i=0;i<B*C*N;i++)
269       mask[i] = 1;
270 #endif
271    /* Pitch analysis */
272    for (c=0;c<C;c++)
273    {
274       for (i=0;i<N;i++)
275       {
276          in[C*i+c] *= st->window[i];
277          in[C*(B*N+i)+c] *= st->window[N+i];
278       }
279    }
280    find_spectral_pitch(st->fft, &st->psy, in, st->out_mem, MAX_PERIOD, (B+1)*N, C, &pitch_index);
281    
282    /* Compute MDCTs of the pitch part */
283    pitch_power = compute_mdcts(&st->mdct_lookup, st->window, st->out_mem+pitch_index*C, P, N, B, C);
284    
285    /*printf ("%f %f\n", curr_power, pitch_power);*/
286    /*int j;
287    for (j=0;j<B*N;j++)
288       printf ("%f ", X[j]);
289    for (j=0;j<B*N;j++)
290       printf ("%f ", P[j]);
291    printf ("\n");*/
292
293    /* Band normalisation */
294    compute_band_energies(st->mode, X, bandE);
295    normalise_bands(st->mode, X, bandE);
296    /*for (i=0;i<st->mode->nbEBands;i++)printf("%f ", bandE[i]);printf("\n");*/
297    /*for (i=0;i<N*B*C;i++)printf("%f ", X[i]);printf("\n");*/
298
299    quant_energy(st->mode, bandE, st->oldBandE, nbCompressedBytes*8/3, &st->enc);
300
301    if (C==2)
302    {
303       stereo_mix(st->mode, X, bandE, 1);
304    }
305
306    /* Check if we can safely use the pitch (i.e. effective gain isn't too high) */
307    if (curr_power + 1e5f < 10.f*pitch_power)
308    {
309       /* Normalise the pitch vector as well (discard the energies) */
310       VARDECL(float *bandEp);
311       ALLOC(bandEp, st->mode->nbEBands*st->mode->nbChannels, float);
312       compute_band_energies(st->mode, P, bandEp);
313       normalise_bands(st->mode, P, bandEp);
314
315       if (C==2)
316          stereo_mix(st->mode, P, bandE, 1);
317       /* Simulates intensity stereo */
318       /*for (i=30;i<N*B;i++)
319          X[i*C+1] = P[i*C+1] = 0;*/
320
321       /* Pitch prediction */
322       compute_pitch_gain(st->mode, X, P, gains, bandE);
323       has_pitch = quant_pitch(gains, st->mode->nbPBands, &st->enc);
324       if (has_pitch)
325          ec_enc_uint(&st->enc, pitch_index, MAX_PERIOD-(B+1)*N);
326    } else {
327       /* No pitch, so we just pretend we found a gain of zero */
328       for (i=0;i<st->mode->nbPBands;i++)
329          gains[i] = 0;
330       ec_enc_uint(&st->enc, 0, 128);
331       for (i=0;i<B*C*N;i++)
332          P[i] = 0;
333    }
334    
335
336    pitch_quant_bands(st->mode, X, P, gains);
337
338    /*for (i=0;i<B*N;i++) printf("%f ",P[i]);printf("\n");*/
339    /* Compute residual that we're going to encode */
340    for (i=0;i<B*C*N;i++)
341       X[i] -= P[i];
342
343    /*float sum=0;
344    for (i=0;i<B*N;i++)
345       sum += X[i]*X[i];
346    printf ("%f\n", sum);*/
347    /* Residual quantisation */
348    quant_bands(st->mode, X, P, mask, nbCompressedBytes*8, &st->enc);
349    
350    if (C==2)
351       stereo_mix(st->mode, X, bandE, -1);
352
353    renormalise_bands(st->mode, X);
354    /* Synthesis */
355    denormalise_bands(st->mode, X, bandE);
356
357
358    CELT_MOVE(st->out_mem, st->out_mem+C*B*N, C*(MAX_PERIOD-B*N));
359
360    compute_inv_mdcts(&st->mdct_lookup, st->window, X, st->out_mem, st->mdct_overlap, N, st->overlap, B, C);
361    /* De-emphasis and put everything back at the right place in the synthesis history */
362    for (c=0;c<C;c++)
363    {
364       for (i=0;i<B;i++)
365       {
366          int j;
367          for (j=0;j<N;j++)
368          {
369             float tmp = st->out_mem[C*(MAX_PERIOD+(i-B)*N)+C*j+c] + st->preemph*st->preemph_memD[c];
370             st->preemph_memD[c] = tmp;
371             if (tmp > 32767) tmp = 32767;
372             if (tmp < -32767) tmp = -32767;
373             pcm[C*i*N+C*j+c] = (short)floor(.5+tmp);
374          }
375       }
376    }
377    
378    if (ec_enc_tell(&st->enc, 0) < nbCompressedBytes*8 - 7)
379       celt_warning_int ("many unused bits: ", nbCompressedBytes*8-ec_enc_tell(&st->enc, 0));
380    /*printf ("%d\n", ec_enc_tell(&st->enc, 0)-8*nbCompressedBytes);*/
381    /* Finishing the stream with a 0101... pattern so that the decoder can check is everything's right */
382    {
383       int val = 0;
384       while (ec_enc_tell(&st->enc, 0) < nbCompressedBytes*8)
385       {
386          ec_enc_uint(&st->enc, val, 2);
387          val = 1-val;
388       }
389    }
390    ec_enc_done(&st->enc);
391    {
392       unsigned char *data;
393       int nbBytes = ec_byte_bytes(&st->buf);
394       if (nbBytes > nbCompressedBytes)
395       {
396          celt_warning_int ("got too many bytes:", nbBytes);
397          return CELT_INTERNAL_ERROR;
398       }
399       /*printf ("%d\n", *nbBytes);*/
400       data = ec_byte_get_buffer(&st->buf);
401       for (i=0;i<nbBytes;i++)
402          compressed[i] = data[i];
403       for (;i<nbCompressedBytes;i++)
404          compressed[i] = 0;
405    }
406    /* Reset the packing for the next encoding */
407    ec_byte_reset(&st->buf);
408    ec_enc_init(&st->enc,&st->buf);
409
410    return nbCompressedBytes;
411 }
412
413
414 /****************************************************************************/
415 /*                                                                          */
416 /*                                DECODER                                   */
417 /*                                                                          */
418 /****************************************************************************/
419
420
421 /** Decoder state 
422  @brief Decoder state
423  */
424 struct CELTDecoder {
425    const CELTMode *mode;
426    int frame_size;
427    int block_size;
428    int nb_blocks;
429    int overlap;
430
431    ec_byte_buffer buf;
432    ec_enc         enc;
433
434    float preemph;
435    float *preemph_memD;
436    
437    mdct_lookup mdct_lookup;
438    
439    float *window;
440    float *mdct_overlap;
441    float *out_mem;
442
443    float *oldBandE;
444    
445    int last_pitch_index;
446 };
447
448 CELTDecoder *celt_decoder_create(const CELTMode *mode)
449 {
450    int i, N, B, C, N4;
451    CELTDecoder *st;
452    N = mode->mdctSize;
453    B = mode->nbMdctBlocks;
454    C = mode->nbChannels;
455    st = celt_alloc(sizeof(CELTDecoder));
456    
457    st->mode = mode;
458    st->frame_size = B*N;
459    st->block_size = N;
460    st->nb_blocks  = B;
461    st->overlap = mode->overlap;
462
463    N4 = (N-st->overlap)/2;
464    
465    mdct_init(&st->mdct_lookup, 2*N);
466    
467    st->window = celt_alloc(2*N*sizeof(float));
468    st->mdct_overlap = celt_alloc(N*C*sizeof(float));
469    st->out_mem = celt_alloc(MAX_PERIOD*C*sizeof(float));
470
471    for (i=0;i<2*N;i++)
472       st->window[i] = 0;
473    for (i=0;i<st->overlap;i++)
474       st->window[N4+i] = st->window[2*N-N4-i-1] 
475             = sin(.5*M_PI* sin(.5*M_PI*(i+.5)/st->overlap) * sin(.5*M_PI*(i+.5)/st->overlap));
476    for (i=0;i<2*N4;i++)
477       st->window[N-N4+i] = 1;
478    
479    st->oldBandE = celt_alloc(C*mode->nbEBands*sizeof(float));
480
481    st->preemph = 0.8;
482    st->preemph_memD = celt_alloc(C*sizeof(float));;
483
484    st->last_pitch_index = 0;
485    return st;
486 }
487
488 void celt_decoder_destroy(CELTDecoder *st)
489 {
490    if (st == NULL)
491    {
492       celt_warning("NULL passed to celt_encoder_destroy");
493       return;
494    }
495
496    mdct_clear(&st->mdct_lookup);
497
498    celt_free(st->window);
499    celt_free(st->mdct_overlap);
500    celt_free(st->out_mem);
501    
502    celt_free(st->oldBandE);
503    
504    celt_free(st->preemph_memD);
505
506    celt_free(st);
507 }
508
509 static void celt_decode_lost(CELTDecoder *st, short *pcm)
510 {
511    int i, c, N, B, C;
512    int pitch_index;
513    VARDECL(float *X);
514    N = st->block_size;
515    B = st->nb_blocks;
516    C = st->mode->nbChannels;
517    ALLOC(X,C*B*N, float);         /**< Interleaved signal MDCTs */
518    
519    pitch_index = st->last_pitch_index;
520    
521    /* Use the pitch MDCT as the "guessed" signal */
522    compute_mdcts(&st->mdct_lookup, st->window, st->out_mem+pitch_index*C, X, N, B, C);
523
524    CELT_MOVE(st->out_mem, st->out_mem+C*B*N, C*(MAX_PERIOD-B*N));
525    /* Compute inverse MDCTs */
526    compute_inv_mdcts(&st->mdct_lookup, st->window, X, st->out_mem, st->mdct_overlap, N, st->overlap, B, C);
527
528    for (c=0;c<C;c++)
529    {
530       for (i=0;i<B;i++)
531       {
532          int j;
533          for (j=0;j<N;j++)
534          {
535             float tmp = st->out_mem[C*(MAX_PERIOD+(i-B)*N)+C*j+c] + st->preemph*st->preemph_memD[c];
536             st->preemph_memD[c] = tmp;
537             if (tmp > 32767) tmp = 32767;
538             if (tmp < -32767) tmp = -32767;
539             pcm[C*i*N+C*j+c] = (short)floor(.5+tmp);
540          }
541       }
542    }
543 }
544
545 int celt_decode(CELTDecoder *st, unsigned char *data, int len, celt_int16_t *pcm)
546 {
547    int i, c, N, B, C;
548    int has_pitch;
549    int pitch_index;
550    ec_dec dec;
551    ec_byte_buffer buf;
552    VARDECL(float *X);
553    VARDECL(float *P);
554    VARDECL(float *bandE);
555    VARDECL(float *gains);
556    N = st->block_size;
557    B = st->nb_blocks;
558    C = st->mode->nbChannels;
559    
560    ALLOC(X, C*B*N, float);         /**< Interleaved signal MDCTs */
561    ALLOC(P, C*B*N, float);         /**< Interleaved pitch MDCTs*/
562    ALLOC(bandE, st->mode->nbEBands*C, float);
563    ALLOC(gains, st->mode->nbPBands, float);
564    
565    if (data == NULL)
566    {
567       celt_decode_lost(st, pcm);
568       return 0;
569    }
570    
571    ec_byte_readinit(&buf,data,len);
572    ec_dec_init(&dec,&buf);
573    
574    /* Get band energies */
575    unquant_energy(st->mode, bandE, st->oldBandE, len*8/3, &dec);
576    
577    /* Get the pitch gains */
578    has_pitch = unquant_pitch(gains, st->mode->nbPBands, &dec);
579    
580    /* Get the pitch index */
581    if (has_pitch)
582    {
583       pitch_index = ec_dec_uint(&dec, MAX_PERIOD-(B+1)*N);
584       st->last_pitch_index = pitch_index;
585    } else {
586       /* FIXME: We could be more intelligent here and just not compute the MDCT */
587       pitch_index = 0;
588    }
589    
590    /* Pitch MDCT */
591    compute_mdcts(&st->mdct_lookup, st->window, st->out_mem+pitch_index*C, P, N, B, C);
592
593    {
594       VARDECL(float *bandEp);
595       ALLOC(bandEp, st->mode->nbEBands*C, float);
596       compute_band_energies(st->mode, P, bandEp);
597       normalise_bands(st->mode, P, bandEp);
598    }
599
600    if (C==2)
601       stereo_mix(st->mode, P, bandE, 1);
602
603    /* Apply pitch gains */
604    pitch_quant_bands(st->mode, X, P, gains);
605
606    /* Decode fixed codebook and merge with pitch */
607    unquant_bands(st->mode, X, P, len*8, &dec);
608
609    if (C==2)
610       stereo_mix(st->mode, X, bandE, -1);
611
612    renormalise_bands(st->mode, X);
613    
614    /* Synthesis */
615    denormalise_bands(st->mode, X, bandE);
616
617
618    CELT_MOVE(st->out_mem, st->out_mem+C*B*N, C*(MAX_PERIOD-B*N));
619    /* Compute inverse MDCTs */
620    compute_inv_mdcts(&st->mdct_lookup, st->window, X, st->out_mem, st->mdct_overlap, N, st->overlap, B, C);
621
622    for (c=0;c<C;c++)
623    {
624       for (i=0;i<B;i++)
625       {
626          int j;
627          for (j=0;j<N;j++)
628          {
629             float tmp = st->out_mem[C*(MAX_PERIOD+(i-B)*N)+C*j+c] + st->preemph*st->preemph_memD[c];
630             st->preemph_memD[c] = tmp;
631             if (tmp > 32767) tmp = 32767;
632             if (tmp < -32767) tmp = -32767;
633             pcm[C*i*N+C*j+c] = (short)floor(.5+tmp);
634          }
635       }
636    }
637
638    {
639       int val = 0;
640       while (ec_dec_tell(&dec, 0) < len*8)
641       {
642          if (ec_dec_uint(&dec, 2) != val)
643          {
644             celt_warning("decode error");
645             return CELT_CORRUPTED_DATA;
646          }
647          val = 1-val;
648       }
649    }
650
651    return 0;
652    /*printf ("\n");*/
653 }
654