media/libopus/celt/modes.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/libopus/celt/modes.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,438 @@
     1.4 +/* Copyright (c) 2007-2008 CSIRO
     1.5 +   Copyright (c) 2007-2009 Xiph.Org Foundation
     1.6 +   Copyright (c) 2008 Gregory Maxwell
     1.7 +   Written by Jean-Marc Valin and Gregory Maxwell */
     1.8 +/*
     1.9 +   Redistribution and use in source and binary forms, with or without
    1.10 +   modification, are permitted provided that the following conditions
    1.11 +   are met:
    1.12 +
    1.13 +   - Redistributions of source code must retain the above copyright
    1.14 +   notice, this list of conditions and the following disclaimer.
    1.15 +
    1.16 +   - Redistributions in binary form must reproduce the above copyright
    1.17 +   notice, this list of conditions and the following disclaimer in the
    1.18 +   documentation and/or other materials provided with the distribution.
    1.19 +
    1.20 +   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.21 +   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.22 +   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.23 +   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
    1.24 +   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    1.25 +   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    1.26 +   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    1.27 +   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    1.28 +   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    1.29 +   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    1.30 +   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.31 +*/
    1.32 +
    1.33 +#ifdef HAVE_CONFIG_H
    1.34 +#include "config.h"
    1.35 +#endif
    1.36 +
    1.37 +#include "celt.h"
    1.38 +#include "modes.h"
    1.39 +#include "rate.h"
    1.40 +#include "os_support.h"
    1.41 +#include "stack_alloc.h"
    1.42 +#include "quant_bands.h"
    1.43 +
    1.44 +static const opus_int16 eband5ms[] = {
    1.45 +/*0  200 400 600 800  1k 1.2 1.4 1.6  2k 2.4 2.8 3.2  4k 4.8 5.6 6.8  8k 9.6 12k 15.6 */
    1.46 +  0,  1,  2,  3,  4,  5,  6,  7,  8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100
    1.47 +};
    1.48 +
    1.49 +/* Alternate tuning (partially derived from Vorbis) */
    1.50 +#define BITALLOC_SIZE 11
    1.51 +/* Bit allocation table in units of 1/32 bit/sample (0.1875 dB SNR) */
    1.52 +static const unsigned char band_allocation[] = {
    1.53 +/*0  200 400 600 800  1k 1.2 1.4 1.6  2k 2.4 2.8 3.2  4k 4.8 5.6 6.8  8k 9.6 12k 15.6 */
    1.54 +  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    1.55 + 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10,  0,  0,  0,  0,  0,  0,  0,  0,
    1.56 +110,100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12,  0,  0,  0,  0,  0,  0,
    1.57 +118,110,103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15,  4,  0,  0,  0,  0,
    1.58 +126,119,112,104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12,  1,  0,  0,
    1.59 +134,127,120,114,103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10,  1,
    1.60 +144,137,130,124,113,107,101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15,  1,
    1.61 +152,145,138,132,123,117,111,105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20,  1,
    1.62 +162,155,148,142,133,127,121,115,108,102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30,  1,
    1.63 +172,165,158,152,143,137,131,125,118,112,106,100, 94, 87, 81, 75, 69, 63, 56, 45, 20,
    1.64 +200,200,200,200,200,200,200,200,198,193,188,183,178,173,168,163,158,153,148,129,104,
    1.65 +};
    1.66 +
    1.67 +#ifndef CUSTOM_MODES_ONLY
    1.68 + #ifdef FIXED_POINT
    1.69 +  #include "static_modes_fixed.h"
    1.70 + #else
    1.71 +  #include "static_modes_float.h"
    1.72 + #endif
    1.73 +#endif /* CUSTOM_MODES_ONLY */
    1.74 +
    1.75 +#ifndef M_PI
    1.76 +#define M_PI 3.141592653
    1.77 +#endif
    1.78 +
    1.79 +#ifdef CUSTOM_MODES
    1.80 +
    1.81 +/* Defining 25 critical bands for the full 0-20 kHz audio bandwidth
    1.82 +   Taken from http://ccrma.stanford.edu/~jos/bbt/Bark_Frequency_Scale.html */
    1.83 +#define BARK_BANDS 25
    1.84 +static const opus_int16 bark_freq[BARK_BANDS+1] = {
    1.85 +      0,   100,   200,   300,   400,
    1.86 +    510,   630,   770,   920,  1080,
    1.87 +   1270,  1480,  1720,  2000,  2320,
    1.88 +   2700,  3150,  3700,  4400,  5300,
    1.89 +   6400,  7700,  9500, 12000, 15500,
    1.90 +  20000};
    1.91 +
    1.92 +static opus_int16 *compute_ebands(opus_int32 Fs, int frame_size, int res, int *nbEBands)
    1.93 +{
    1.94 +   opus_int16 *eBands;
    1.95 +   int i, j, lin, low, high, nBark, offset=0;
    1.96 +
    1.97 +   /* All modes that have 2.5 ms short blocks use the same definition */
    1.98 +   if (Fs == 400*(opus_int32)frame_size)
    1.99 +   {
   1.100 +      *nbEBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1;
   1.101 +      eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+1));
   1.102 +      for (i=0;i<*nbEBands+1;i++)
   1.103 +         eBands[i] = eband5ms[i];
   1.104 +      return eBands;
   1.105 +   }
   1.106 +   /* Find the number of critical bands supported by our sampling rate */
   1.107 +   for (nBark=1;nBark<BARK_BANDS;nBark++)
   1.108 +    if (bark_freq[nBark+1]*2 >= Fs)
   1.109 +       break;
   1.110 +
   1.111 +   /* Find where the linear part ends (i.e. where the spacing is more than min_width */
   1.112 +   for (lin=0;lin<nBark;lin++)
   1.113 +      if (bark_freq[lin+1]-bark_freq[lin] >= res)
   1.114 +         break;
   1.115 +
   1.116 +   low = (bark_freq[lin]+res/2)/res;
   1.117 +   high = nBark-lin;
   1.118 +   *nbEBands = low+high;
   1.119 +   eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+2));
   1.120 +
   1.121 +   if (eBands==NULL)
   1.122 +      return NULL;
   1.123 +
   1.124 +   /* Linear spacing (min_width) */
   1.125 +   for (i=0;i<low;i++)
   1.126 +      eBands[i] = i;
   1.127 +   if (low>0)
   1.128 +      offset = eBands[low-1]*res - bark_freq[lin-1];
   1.129 +   /* Spacing follows critical bands */
   1.130 +   for (i=0;i<high;i++)
   1.131 +   {
   1.132 +      int target = bark_freq[lin+i];
   1.133 +      /* Round to an even value */
   1.134 +      eBands[i+low] = (target+offset/2+res)/(2*res)*2;
   1.135 +      offset = eBands[i+low]*res - target;
   1.136 +   }
   1.137 +   /* Enforce the minimum spacing at the boundary */
   1.138 +   for (i=0;i<*nbEBands;i++)
   1.139 +      if (eBands[i] < i)
   1.140 +         eBands[i] = i;
   1.141 +   /* Round to an even value */
   1.142 +   eBands[*nbEBands] = (bark_freq[nBark]+res)/(2*res)*2;
   1.143 +   if (eBands[*nbEBands] > frame_size)
   1.144 +      eBands[*nbEBands] = frame_size;
   1.145 +   for (i=1;i<*nbEBands-1;i++)
   1.146 +   {
   1.147 +      if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1])
   1.148 +      {
   1.149 +         eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2;
   1.150 +      }
   1.151 +   }
   1.152 +   /* Remove any empty bands. */
   1.153 +   for (i=j=0;i<*nbEBands;i++)
   1.154 +      if(eBands[i+1]>eBands[j])
   1.155 +         eBands[++j]=eBands[i+1];
   1.156 +   *nbEBands=j;
   1.157 +
   1.158 +   for (i=1;i<*nbEBands;i++)
   1.159 +   {
   1.160 +      /* Every band must be smaller than the last band. */
   1.161 +      celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]);
   1.162 +      /* Each band must be no larger than twice the size of the previous one. */
   1.163 +      celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1]));
   1.164 +   }
   1.165 +
   1.166 +   return eBands;
   1.167 +}
   1.168 +
   1.169 +static void compute_allocation_table(CELTMode *mode)
   1.170 +{
   1.171 +   int i, j;
   1.172 +   unsigned char *allocVectors;
   1.173 +   int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1;
   1.174 +
   1.175 +   mode->nbAllocVectors = BITALLOC_SIZE;
   1.176 +   allocVectors = opus_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands));
   1.177 +   if (allocVectors==NULL)
   1.178 +      return;
   1.179 +
   1.180 +   /* Check for standard mode */
   1.181 +   if (mode->Fs == 400*(opus_int32)mode->shortMdctSize)
   1.182 +   {
   1.183 +      for (i=0;i<BITALLOC_SIZE*mode->nbEBands;i++)
   1.184 +         allocVectors[i] = band_allocation[i];
   1.185 +      mode->allocVectors = allocVectors;
   1.186 +      return;
   1.187 +   }
   1.188 +   /* If not the standard mode, interpolate */
   1.189 +   /* Compute per-codec-band allocation from per-critical-band matrix */
   1.190 +   for (i=0;i<BITALLOC_SIZE;i++)
   1.191 +   {
   1.192 +      for (j=0;j<mode->nbEBands;j++)
   1.193 +      {
   1.194 +         int k;
   1.195 +         for (k=0;k<maxBands;k++)
   1.196 +         {
   1.197 +            if (400*(opus_int32)eband5ms[k] > mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize)
   1.198 +               break;
   1.199 +         }
   1.200 +         if (k>maxBands-1)
   1.201 +            allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1];
   1.202 +         else {
   1.203 +            opus_int32 a0, a1;
   1.204 +            a1 = mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize - 400*(opus_int32)eband5ms[k-1];
   1.205 +            a0 = 400*(opus_int32)eband5ms[k] - mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize;
   1.206 +            allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1]
   1.207 +                                             + a1*band_allocation[i*maxBands+k])/(a0+a1);
   1.208 +         }
   1.209 +      }
   1.210 +   }
   1.211 +
   1.212 +   /*printf ("\n");
   1.213 +   for (i=0;i<BITALLOC_SIZE;i++)
   1.214 +   {
   1.215 +      for (j=0;j<mode->nbEBands;j++)
   1.216 +         printf ("%d ", allocVectors[i*mode->nbEBands+j]);
   1.217 +      printf ("\n");
   1.218 +   }
   1.219 +   exit(0);*/
   1.220 +
   1.221 +   mode->allocVectors = allocVectors;
   1.222 +}
   1.223 +
   1.224 +#endif /* CUSTOM_MODES */
   1.225 +
   1.226 +CELTMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error)
   1.227 +{
   1.228 +   int i;
   1.229 +#ifdef CUSTOM_MODES
   1.230 +   CELTMode *mode=NULL;
   1.231 +   int res;
   1.232 +   opus_val16 *window;
   1.233 +   opus_int16 *logN;
   1.234 +   int LM;
   1.235 +   ALLOC_STACK;
   1.236 +#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA)
   1.237 +   if (global_stack==NULL)
   1.238 +      goto failure;
   1.239 +#endif
   1.240 +#endif
   1.241 +
   1.242 +#ifndef CUSTOM_MODES_ONLY
   1.243 +   for (i=0;i<TOTAL_MODES;i++)
   1.244 +   {
   1.245 +      int j;
   1.246 +      for (j=0;j<4;j++)
   1.247 +      {
   1.248 +         if (Fs == static_mode_list[i]->Fs &&
   1.249 +               (frame_size<<j) == static_mode_list[i]->shortMdctSize*static_mode_list[i]->nbShortMdcts)
   1.250 +         {
   1.251 +            if (error)
   1.252 +               *error = OPUS_OK;
   1.253 +            return (CELTMode*)static_mode_list[i];
   1.254 +         }
   1.255 +      }
   1.256 +   }
   1.257 +#endif /* CUSTOM_MODES_ONLY */
   1.258 +
   1.259 +#ifndef CUSTOM_MODES
   1.260 +   if (error)
   1.261 +      *error = OPUS_BAD_ARG;
   1.262 +   return NULL;
   1.263 +#else
   1.264 +
   1.265 +   /* The good thing here is that permutation of the arguments will automatically be invalid */
   1.266 +
   1.267 +   if (Fs < 8000 || Fs > 96000)
   1.268 +   {
   1.269 +      if (error)
   1.270 +         *error = OPUS_BAD_ARG;
   1.271 +      return NULL;
   1.272 +   }
   1.273 +   if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0)
   1.274 +   {
   1.275 +      if (error)
   1.276 +         *error = OPUS_BAD_ARG;
   1.277 +      return NULL;
   1.278 +   }
   1.279 +   /* Frames of less than 1ms are not supported. */
   1.280 +   if ((opus_int32)frame_size*1000 < Fs)
   1.281 +   {
   1.282 +      if (error)
   1.283 +         *error = OPUS_BAD_ARG;
   1.284 +      return NULL;
   1.285 +   }
   1.286 +
   1.287 +   if ((opus_int32)frame_size*75 >= Fs && (frame_size%16)==0)
   1.288 +   {
   1.289 +     LM = 3;
   1.290 +   } else if ((opus_int32)frame_size*150 >= Fs && (frame_size%8)==0)
   1.291 +   {
   1.292 +     LM = 2;
   1.293 +   } else if ((opus_int32)frame_size*300 >= Fs && (frame_size%4)==0)
   1.294 +   {
   1.295 +     LM = 1;
   1.296 +   } else
   1.297 +   {
   1.298 +     LM = 0;
   1.299 +   }
   1.300 +
   1.301 +   /* Shorts longer than 3.3ms are not supported. */
   1.302 +   if ((opus_int32)(frame_size>>LM)*300 > Fs)
   1.303 +   {
   1.304 +      if (error)
   1.305 +         *error = OPUS_BAD_ARG;
   1.306 +      return NULL;
   1.307 +   }
   1.308 +
   1.309 +   mode = opus_alloc(sizeof(CELTMode));
   1.310 +   if (mode==NULL)
   1.311 +      goto failure;
   1.312 +   mode->Fs = Fs;
   1.313 +
   1.314 +   /* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis
   1.315 +      is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should
   1.316 +      approximate that. */
   1.317 +   if(Fs < 12000) /* 8 kHz */
   1.318 +   {
   1.319 +      mode->preemph[0] =  QCONST16(0.3500061035f, 15);
   1.320 +      mode->preemph[1] = -QCONST16(0.1799926758f, 15);
   1.321 +      mode->preemph[2] =  QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */
   1.322 +      mode->preemph[3] =  QCONST16(3.6765136719f, 13);
   1.323 +   } else if(Fs < 24000) /* 16 kHz */
   1.324 +   {
   1.325 +      mode->preemph[0] =  QCONST16(0.6000061035f, 15);
   1.326 +      mode->preemph[1] = -QCONST16(0.1799926758f, 15);
   1.327 +      mode->preemph[2] =  QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */
   1.328 +      mode->preemph[3] =  QCONST16(2.2598876953f, 13);
   1.329 +   } else if(Fs < 40000) /* 32 kHz */
   1.330 +   {
   1.331 +      mode->preemph[0] =  QCONST16(0.7799987793f, 15);
   1.332 +      mode->preemph[1] = -QCONST16(0.1000061035f, 15);
   1.333 +      mode->preemph[2] =  QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */
   1.334 +      mode->preemph[3] =  QCONST16(1.3333740234f, 13);
   1.335 +   } else /* 48 kHz */
   1.336 +   {
   1.337 +      mode->preemph[0] =  QCONST16(0.8500061035f, 15);
   1.338 +      mode->preemph[1] =  QCONST16(0.0f, 15);
   1.339 +      mode->preemph[2] =  QCONST16(1.f, SIG_SHIFT);
   1.340 +      mode->preemph[3] =  QCONST16(1.f, 13);
   1.341 +   }
   1.342 +
   1.343 +   mode->maxLM = LM;
   1.344 +   mode->nbShortMdcts = 1<<LM;
   1.345 +   mode->shortMdctSize = frame_size/mode->nbShortMdcts;
   1.346 +   res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize);
   1.347 +
   1.348 +   mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands);
   1.349 +   if (mode->eBands==NULL)
   1.350 +      goto failure;
   1.351 +#if !defined(SMALL_FOOTPRINT)
   1.352 +   /* Make sure we don't allocate a band larger than our PVQ table.
   1.353 +      208 should be enough, but let's be paranoid. */
   1.354 +   if ((mode->eBands[mode->nbEBands] - mode->eBands[mode->nbEBands-1])<<LM >
   1.355 +    208) {
   1.356 +       goto failure;
   1.357 +   }
   1.358 +#endif
   1.359 +
   1.360 +   mode->effEBands = mode->nbEBands;
   1.361 +   while (mode->eBands[mode->effEBands] > mode->shortMdctSize)
   1.362 +      mode->effEBands--;
   1.363 +
   1.364 +   /* Overlap must be divisible by 4 */
   1.365 +   mode->overlap = ((mode->shortMdctSize>>2)<<2);
   1.366 +
   1.367 +   compute_allocation_table(mode);
   1.368 +   if (mode->allocVectors==NULL)
   1.369 +      goto failure;
   1.370 +
   1.371 +   window = (opus_val16*)opus_alloc(mode->overlap*sizeof(opus_val16));
   1.372 +   if (window==NULL)
   1.373 +      goto failure;
   1.374 +
   1.375 +#ifndef FIXED_POINT
   1.376 +   for (i=0;i<mode->overlap;i++)
   1.377 +      window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap));
   1.378 +#else
   1.379 +   for (i=0;i<mode->overlap;i++)
   1.380 +      window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap))));
   1.381 +#endif
   1.382 +   mode->window = window;
   1.383 +
   1.384 +   logN = (opus_int16*)opus_alloc(mode->nbEBands*sizeof(opus_int16));
   1.385 +   if (logN==NULL)
   1.386 +      goto failure;
   1.387 +
   1.388 +   for (i=0;i<mode->nbEBands;i++)
   1.389 +      logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES);
   1.390 +   mode->logN = logN;
   1.391 +
   1.392 +   compute_pulse_cache(mode, mode->maxLM);
   1.393 +
   1.394 +   if (clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts,
   1.395 +           mode->maxLM) == 0)
   1.396 +      goto failure;
   1.397 +
   1.398 +   if (error)
   1.399 +      *error = OPUS_OK;
   1.400 +
   1.401 +   return mode;
   1.402 +failure:
   1.403 +   if (error)
   1.404 +      *error = OPUS_ALLOC_FAIL;
   1.405 +   if (mode!=NULL)
   1.406 +      opus_custom_mode_destroy(mode);
   1.407 +   return NULL;
   1.408 +#endif /* !CUSTOM_MODES */
   1.409 +}
   1.410 +
   1.411 +#ifdef CUSTOM_MODES
   1.412 +void opus_custom_mode_destroy(CELTMode *mode)
   1.413 +{
   1.414 +   if (mode == NULL)
   1.415 +      return;
   1.416 +#ifndef CUSTOM_MODES_ONLY
   1.417 +   {
   1.418 +     int i;
   1.419 +     for (i=0;i<TOTAL_MODES;i++)
   1.420 +     {
   1.421 +        if (mode == static_mode_list[i])
   1.422 +        {
   1.423 +           return;
   1.424 +        }
   1.425 +     }
   1.426 +   }
   1.427 +#endif /* CUSTOM_MODES_ONLY */
   1.428 +   opus_free((opus_int16*)mode->eBands);
   1.429 +   opus_free((opus_int16*)mode->allocVectors);
   1.430 +
   1.431 +   opus_free((opus_val16*)mode->window);
   1.432 +   opus_free((opus_int16*)mode->logN);
   1.433 +
   1.434 +   opus_free((opus_int16*)mode->cache.index);
   1.435 +   opus_free((unsigned char*)mode->cache.bits);
   1.436 +   opus_free((unsigned char*)mode->cache.caps);
   1.437 +   clt_mdct_clear(&mode->mdct);
   1.438 +
   1.439 +   opus_free((CELTMode *)mode);
   1.440 +}
   1.441 +#endif

mercurial