Exemple #1
0
static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
                    size_t *isamp, size_t *osamp)
{
  priv_t * l = (priv_t *) effp->priv;
  int len =  (*isamp > *osamp) ? *osamp : *isamp;
  int filechans = effp->out_signal.channels;
  int idone,odone;

  for (idone = 0,odone = 0; idone < len; ibuf += filechans) {
    int chan;

    /* Maintain the volume fields by simulating a leaky pump circuit */
    for (chan = 0; chan < filechans; ++chan) {
      if (l->expectedChannels == 1 && filechans > 1) {
        /* User is expecting same compander for all channels */
        int i;
        double maxsamp = 0.0;
        for (i = 0; i < filechans; ++i) {
          double rect = fabs((double)ibuf[i]);
          if (rect > maxsamp) maxsamp = rect;
        }
        doVolume(&l->channels[0].volume, maxsamp, l, 0);
        break;
      } else
        doVolume(&l->channels[chan].volume, fabs((double)ibuf[chan]), l, chan);
    }

    /* Volume memory is updated: perform compand */
    for (chan = 0; chan < filechans; ++chan) {
      int ch = l->expectedChannels > 1 ? chan : 0;
      double level_in_lin = l->channels[ch].volume;
      double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin);
      double checkbuf;

      if (l->delay_buf_size <= 0) {
        checkbuf = ibuf[chan] * level_out_lin;
        SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
        obuf[odone++] = checkbuf;
        idone++;
      } else {
        if (l->delay_buf_cnt >= l->delay_buf_size) {
          l->delay_buf_full=1; /* delay buffer is now definitely full */
          checkbuf = l->delay_buf[l->delay_buf_index] * level_out_lin;
          SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
          obuf[odone] = checkbuf;
          odone++;
          idone++;
        } else {
          l->delay_buf_cnt++;
          idone++; /* no "odone++" because we did not fill obuf[...] */
        }
        l->delay_buf[l->delay_buf_index++] = ibuf[chan];
        l->delay_buf_index %= l->delay_buf_size;
      }
    }
  }

  *isamp = idone; *osamp = odone;
  return (SOX_SUCCESS);
}
Exemple #2
0
static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
                size_t *isamp, size_t *osamp)
{
    priv_t * mixer = (priv_t *) effp->priv;
    size_t len, done;
    int ichan, ochan;
    int i, j;
    double samp;

    ichan = effp->in_signal.channels;
    ochan = effp->out_signal.channels;
    len = *isamp / ichan;
    if (len > *osamp / ochan)
        len = *osamp / ochan;
    for (done = 0; done < len; done++, ibuf += ichan, obuf += ochan) {
        for (j = 0; j < ochan; j++) {
            samp = 0.0;
            for (i = 0; i < ichan; i++)
                samp += ibuf[i] * mixer->sources[mixer->mix == MIX_CENTER? 0 : i][j];
            SOX_SAMPLE_CLIP_COUNT(samp, effp->clips);
            obuf[j] = samp;
        }
    }
    *isamp = len * ichan;
    *osamp = len * ochan;
    return (SOX_SUCCESS);
}
Exemple #3
0
/*
 * Process data.
 */
static int sox_dcshift_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
                    size_t *isamp, size_t *osamp)
{
    priv_t * dcs = (priv_t *) effp->priv;
    double dcshift = dcs->dcshift;
    double limitergain = dcs->limitergain;
    double limiterthreshhold = dcs->limiterthreshhold;
    double sample;
    size_t len;

    len = min(*osamp, *isamp);

    /* report back dealt with amount. */
    *isamp = len; *osamp = len;

    if (dcs->uselimiter)
    {
        dcs->totalprocessed += len;

        for (;len>0; len--)
            {
                sample = *ibuf++;

                if (sample > limiterthreshhold && dcshift > 0)
                {
                        sample =  (sample - limiterthreshhold) * limitergain / (SOX_SAMPLE_MAX - limiterthreshhold) + limiterthreshhold + dcshift;
                        dcs->limited++;
                }
                else if (sample < -limiterthreshhold && dcshift < 0)
                {
                        /* Note this should really be SOX_SAMPLE_MIN but
                         * the clip() below will take care of the overflow.
                         */
                        sample =  (sample + limiterthreshhold) * limitergain / (SOX_SAMPLE_MAX - limiterthreshhold) - limiterthreshhold + dcshift;
                        dcs->limited++;
                }
                else
                {
                        /* Note this should consider SOX_SAMPLE_MIN but
                         * the clip() below will take care of the overflow.
                         */
                        sample = dcshift * SOX_SAMPLE_MAX + sample;
                }

                SOX_SAMPLE_CLIP_COUNT(sample, effp->clips);
                *obuf++ = sample;
            }
    }
    else for (; len > 0; --len) {            /* quite basic, with clipping */
      double d = dcshift * (SOX_SAMPLE_MAX + 1.) + *ibuf++;
      *obuf++ = SOX_ROUND_CLIP_COUNT(d, effp->clips);
    }
    return SOX_SUCCESS;
}
Exemple #4
0
/*
 * Processed signed long samples from ibuf to obuf.
 * Return number of samples processed.
 */
static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
                     size_t *isamp, size_t *osamp) {
  priv_t * c = (priv_t *) effp->priv;
  comp_band_t * l;
  size_t len = min(*isamp, *osamp);
  size_t band, i;
  sox_sample_t *abuf, *bbuf, *cbuf, *oldabuf, *ibuf_copy;
  double out;

  if (c->band_buf_len < len) {
    c->band_buf1 = lsx_realloc(c->band_buf1,len*sizeof(sox_sample_t));
    c->band_buf2 = lsx_realloc(c->band_buf2,len*sizeof(sox_sample_t));
    c->band_buf3 = lsx_realloc(c->band_buf3,len*sizeof(sox_sample_t));
    c->band_buf_len = len;
  }

  len -= len % effp->out_signal.channels;

  ibuf_copy = lsx_malloc(*isamp * sizeof(sox_sample_t));
  memcpy(ibuf_copy, ibuf, *isamp * sizeof(sox_sample_t));

  /* split ibuf into bands using filters, pipe each band through sox_mcompand_flow_1, then add back together and write to obuf */

  memset(obuf,0,len * sizeof *obuf);
  for (band=0,abuf=ibuf_copy,bbuf=c->band_buf2,cbuf=c->band_buf1;band<c->nBands;++band) {
    l = &c->bands[band];

    if (l->topfreq)
      crossover_flow(effp, &l->filter, abuf, bbuf, cbuf, len);
    else {
      bbuf = abuf;
      abuf = cbuf;
    }
    if (abuf == ibuf_copy)
      abuf = c->band_buf3;
    (void)sox_mcompand_flow_1(effp, c,l,bbuf,abuf,len, (size_t)effp->out_signal.channels);
    for (i=0;i<len;++i)
    {
      out = obuf[i] + abuf[i];
      SOX_SAMPLE_CLIP_COUNT(out, effp->clips);
      obuf[i] = out;
    }
    oldabuf = abuf;
    abuf = cbuf;
    cbuf = oldabuf;
  }

  *isamp = *osamp = len;

  free(ibuf_copy);

  return SOX_SUCCESS;
}
Exemple #5
0
static int sox_mcompand_drain_1(sox_effect_t * effp, priv_t * c, comp_band_t * l, sox_sample_t *obuf, size_t maxdrain)
{
  size_t done;
  double out;

  /*
   * Drain out delay samples.  Note that this loop does all channels.
   */
  for (done = 0;  done < maxdrain  &&  l->delay_buf_cnt > 0;  done++) {
    out = obuf[done] + l->delay_buf[l->delay_buf_ptr++];
    SOX_SAMPLE_CLIP_COUNT(out, effp->clips);
    obuf[done] = out;
    l->delay_buf_ptr %= c->delay_buf_size;
    l->delay_buf_cnt--;
  }

  /* tell caller number of samples played */
  return done;

}
Exemple #6
0
static int sox_mcompand_flow_1(sox_effect_t * effp, priv_t * c, comp_band_t * l, const sox_sample_t *ibuf, sox_sample_t *obuf, size_t len, size_t filechans)
{
  size_t idone, odone;

  for (idone = 0, odone = 0; idone < len; ibuf += filechans) {
    size_t chan;

    /* Maintain the volume fields by simulating a leaky pump circuit */

    if (l->expectedChannels == 1 && filechans > 1) {
      /* User is expecting same compander for all channels */
      double maxsamp = 0.0;
      for (chan = 0; chan < filechans; ++chan) {
        double rect = fabs((double)ibuf[chan]);
        if (rect > maxsamp)
          maxsamp = rect;
      }
      doVolume(&l->volume[0], maxsamp, l, (size_t) 0);
    } else {
      for (chan = 0; chan < filechans; ++chan)
        doVolume(&l->volume[chan], fabs((double)ibuf[chan]), l, chan);
    }

    /* Volume memory is updated: perform compand */
    for (chan = 0; chan < filechans; ++chan) {
      int ch = l->expectedChannels > 1 ? chan : 0;
      double level_in_lin = l->volume[ch];
      double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin);
      double checkbuf;

      if (c->delay_buf_size <= 0) {
        checkbuf = ibuf[chan] * level_out_lin;
        SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
        obuf[odone++] = checkbuf;
        idone++;
      } else {
        /* FIXME: note that this lookahead algorithm is really lame:
           the response to a peak is released before the peak
           arrives. */

        /* because volume application delays differ band to band, but
           total delay doesn't, the volume is applied in an iteration
           preceding that in which the sample goes to obuf, except in
           the band(s) with the longest vol app delay.

           the offset between delay_buf_ptr and the sample to apply
           vol to, is a constant equal to the difference between this
           band's delay and the longest delay of all the bands. */

        if (l->delay_buf_cnt >= l->delay_size) {
          checkbuf = l->delay_buf[(l->delay_buf_ptr + c->delay_buf_size - l->delay_size)%c->delay_buf_size] * level_out_lin;
          SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
          l->delay_buf[(l->delay_buf_ptr + c->delay_buf_size - l->delay_size)%c->delay_buf_size] = checkbuf;
        }
        if (l->delay_buf_cnt >= c->delay_buf_size) {
          obuf[odone] = l->delay_buf[l->delay_buf_ptr];
          odone++;
          idone++;
        } else {
          l->delay_buf_cnt++;
          idone++; /* no "odone++" because we did not fill obuf[...] */
        }
        l->delay_buf[l->delay_buf_ptr++] = ibuf[chan];
        l->delay_buf_ptr %= c->delay_buf_size;
      }
    }
  }

  if (idone != odone || idone != len) {
    /* Emergency brake - will lead to memory corruption otherwise since we
       cannot report back to flow() how many samples were consumed/emitted.
       Additionally, flow() doesn't know how to handle diverging
       sub-compander delays. */
    lsx_fail("Using a compander delay within mcompand is currently not supported");
    exit(1);
    /* FIXME */
  }

  return (SOX_SUCCESS);
}
Exemple #7
0
static int sox_mcompand_flow_1(sox_effect_t * effp, priv_t * c, comp_band_t * l, const sox_sample_t *ibuf, sox_sample_t *obuf, size_t len, size_t filechans)
{
  size_t done, chan;

  for (done = 0; done < len; ibuf += filechans) {

    /* Maintain the volume fields by simulating a leaky pump circuit */

    if (l->expectedChannels == 1 && filechans > 1) {
      /* User is expecting same compander for all channels */
      double maxsamp = 0.0;
      for (chan = 0; chan < filechans; ++chan) {
        double rect = fabs((double)ibuf[chan]);
        if (rect > maxsamp)
          maxsamp = rect;
      }
      doVolume(&l->volume[0], maxsamp, l, (size_t) 0);
    } else {
      for (chan = 0; chan < filechans; ++chan)
        doVolume(&l->volume[chan], fabs((double)ibuf[chan]), l, chan);
    }

    /* Volume memory is updated: perform compand */
    for (chan = 0; chan < filechans; ++chan) {
      int ch = l->expectedChannels > 1 ? chan : 0;
      double level_in_lin = l->volume[ch];
      double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin);
      double checkbuf;

      if (c->delay_buf_size <= 0) {
        checkbuf = ibuf[chan] * level_out_lin;
        SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
        obuf[done++] = checkbuf;

      } else {
        /* FIXME: note that this lookahead algorithm is really lame:
           the response to a peak is released before the peak
           arrives. */

        /* because volume application delays differ band to band, but
           total delay doesn't, the volume is applied in an iteration
           preceding that in which the sample goes to obuf, except in
           the band(s) with the longest vol app delay.

           the offset between delay_buf_ptr and the sample to apply
           vol to, is a constant equal to the difference between this
           band's delay and the longest delay of all the bands. */

        if (l->delay_buf_cnt >= l->delay_size) {
          checkbuf = l->delay_buf[(l->delay_buf_ptr + c->delay_buf_size - l->delay_size)%c->delay_buf_size] * level_out_lin;
          SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
          l->delay_buf[(l->delay_buf_ptr + c->delay_buf_size - l->delay_size)%c->delay_buf_size] = checkbuf;
        }
        if (l->delay_buf_cnt >= c->delay_buf_size)
          obuf[done++] = l->delay_buf[l->delay_buf_ptr];
        else
          l->delay_buf_cnt++;
        l->delay_buf[l->delay_buf_ptr++] = ibuf[chan];
        l->delay_buf_ptr %= c->delay_buf_size;
      }
    }
  }

  return (SOX_SUCCESS);
}
Exemple #8
0
/*
 * Process either isamp or osamp samples, whichever is smaller.
 */
static int sox_pan_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
                size_t *isamp, size_t *osamp)
{
    priv_t * pan = (priv_t *) effp->priv;
    size_t len, done;
    sox_sample_t *ibuf_copy;
    char ich, och;
    double left, right, direction, hdir;

    ibuf_copy = lsx_malloc(*isamp * sizeof(sox_sample_t));
    memcpy(ibuf_copy, ibuf, *isamp * sizeof(sox_sample_t));

    direction   = pan->direction;    /* -1   <=  direction  <= 1   */
    hdir  = 0.5 * direction;  /* -0.5 <=  hdir <= 0.5 */
    left  = 0.5 - hdir; /*  0   <=  left <= 1   */
    right = 0.5 + hdir; /*  0   <= right <= 1   */

    ich = effp->in_signal.channels;
    och = effp->out_signal.channels;

    len = min(*osamp/och,*isamp/ich);

    /* report back how much is processed. */
    *isamp = len*ich;
    *osamp = len*och;

    /* 9 different cases to handle: (1,2,4) X (1,2,4) */
    switch (och) {
    case 1: /* pan on mono channel... not much sense. just avg. */
        switch (ich) {
        case 1: /* simple copy */
            for (done=0; done<len; done++)
                *obuf++ = *ibuf_copy++;
            break;
        case 2: /* average 2 */
            for (done=0; done<len; done++)
            {
                double f;
                f = 0.5*ibuf_copy[0] + 0.5*ibuf_copy[1];
                SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                *obuf++ = f;
                ibuf_copy += 2;
            }
            break;
        case 4: /* average 4 */
            for (done=0; done<len; done++)
            {
                double f;
                f = 0.25*ibuf_copy[0] + 0.25*ibuf_copy[1] +
                        0.25*ibuf_copy[2] + 0.25*ibuf_copy[3];
                SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                *obuf++ = f;
                ibuf_copy += 4;
            }
            break;
        default:
            UNEXPECTED_CHANNELS;
            break;
        } /* end first switch in channel */
        break;
    case 2:
        switch (ich) {
        case 1: /* linear */
            for (done=0; done<len; done++)
            {
                double f;

                f = left * ibuf_copy[0];
                SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                obuf[0] = f;
                f = right * ibuf_copy[0];
                SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                obuf[1] = f;
                obuf += 2;
                ibuf_copy++;
            }
            break;
        case 2: /* linear panorama.
                 * I'm not sure this is the right way to do it.
                 */
            if (direction <= 0.0) /* to the left */
            {
                register double volume, cll, clr, cr;

                volume = 1.0 - 0.5*direction;
                cll = volume*(1.5-left);
                clr = volume*(left-0.5);
                cr  = volume*(1.0+direction);

                for (done=0; done<len; done++)
                {
                    double f;

                    f = cll * ibuf_copy[0] + clr * ibuf_copy[1];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[0] = f;
                    f = cr * ibuf_copy[1];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[1] = f;
                    obuf += 2;
                    ibuf_copy += 2;
                }
            }
            else /* to the right */
            {
                register double volume, cl, crl, crr;

                volume = 1.0 + 0.5*direction;
                cl  = volume*(1.0-direction);
                crl = volume*(right-0.5);
                crr = volume*(1.5-right);

                for (done=0; done<len; done++)
                {
                    double f;

                    f = cl * ibuf_copy[0];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[0] = f;
                    f = crl * ibuf_copy[0] + crr * ibuf_copy[1];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[1] = f;
                    obuf += 2;
                    ibuf_copy += 2;
                }
            }
            break;
        case 4:
            if (direction <= 0.0) /* to the left */
            {
                register double volume, cll, clr, cr;

                volume = 1.0 - 0.5*direction;
                cll = volume*(1.5-left);
                clr = volume*(left-0.5);
                cr  = volume*(1.0+direction);

                for (done=0; done<len; done++)
                {
                    register double ibuf0, ibuf1, f;

                    /* build stereo signal */
                    ibuf0 = 0.5*ibuf_copy[0] + 0.5*ibuf_copy[2];
                    ibuf1 = 0.5*ibuf_copy[1] + 0.5*ibuf_copy[3];

                    /* pan it */
                    f = cll * ibuf0 + clr * ibuf1;
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[0] = f;
                    f = cr * ibuf1;
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[1] = f;
                    obuf += 2;
                    ibuf_copy += 4;
                }
            }
            else /* to the right */
            {
                register double volume, cl, crl, crr;

                volume = 1.0 + 0.5*direction;
                cl  = volume*(1.0-direction);
                crl = volume*(right-0.5);
                crr = volume*(1.5-right);

                for (done=0; done<len; done++)
                {
                    register double ibuf0, ibuf1, f;

                    ibuf0 = 0.5*ibuf_copy[0] + 0.5*ibuf_copy[2];
                    ibuf1 = 0.5*ibuf_copy[1] + 0.5*ibuf_copy[3];

                    f = cl * ibuf0;
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[0] = f;
                    f = crl * ibuf0 + crr * ibuf1;
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[1] = f;
                    obuf += 2;
                    ibuf_copy += 4;
                }
            }
            break;
        default:
            UNEXPECTED_CHANNELS;
            break;
        } /* end second switch in channel */
        break;
    case 4:
        switch (ich) {
        case 1: /* linear */
            {
                register double cr, cl;

                cl = 0.5*left;
                cr = 0.5*right;

                for (done=0; done<len; done++)
                {
                    double f;

                    f = cl * ibuf_copy[0];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[2] = obuf[0] = f;
                    f = cr * ibuf_copy[0];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    ibuf_copy[3] = obuf[1] = f;
                    obuf += 4;
                    ibuf_copy++;
                }
            }
            break;
        case 2: /* simple linear panorama */
            if (direction <= 0.0) /* to the left */
            {
                register double volume, cll, clr, cr;

                volume = 0.5 - 0.25*direction;
                cll = volume * (1.5-left);
                clr = volume * (left-0.5);
                cr  = volume * (1.0+direction);

                for (done=0; done<len; done++)
                {
                    double f;

                    f = cll * ibuf_copy[0] + clr * ibuf_copy[1];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[2] = obuf[0] = f;
                    f = cr * ibuf_copy[1];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    ibuf_copy[3] = obuf[1] = f;
                    obuf += 4;
                    ibuf_copy += 2;
                }
            }
            else /* to the right */
            {
                register double volume, cl, crl, crr;

                volume = 0.5 + 0.25*direction;
                cl  = volume * (1.0-direction);
                crl = volume * (right-0.5);
                crr = volume * (1.5-right);

                for (done=0; done<len; done++)
                {
                    double f;

                    f = cl * ibuf_copy[0];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[2] = obuf[0] =f ;
                    f = crl * ibuf_copy[0] + crr * ibuf_copy[1];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    ibuf_copy[3] = obuf[1] = f;
                    obuf += 4;
                    ibuf_copy += 2;
                }
            }
            break;
        case 4:
            /* maybe I could improve the formula to reverse...
               also, turn only by quarters.
             */
            if (direction <= 0.0) /* to the left */
            {
                register double cown, cright;

                cright = -direction;
                cown = 1.0 + direction;

                for (done=0; done<len; done++)
                {
                    double f;

                    f = cown*ibuf_copy[0] + cright*ibuf_copy[1];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[0] = f;
                    f = cown*ibuf_copy[1] + cright*ibuf_copy[3];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[1] = f;
                    f = cown*ibuf_copy[2] + cright*ibuf_copy[0];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[2] = f;
                    f = cown*ibuf_copy[3] + cright*ibuf_copy[2];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[3] = f;
                    obuf += 4;
                    ibuf_copy += 4;
                }
            }
            else /* to the right */
            {
                register double cleft, cown;

                cleft = direction;
                cown = 1.0 - direction;

                for (done=0; done<len; done++)
                {
                    double f;

                    f = cleft*ibuf_copy[2] + cown*ibuf_copy[0];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[0] = f;
                    f = cleft*ibuf_copy[0] + cown*ibuf_copy[1];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[1] = f;
                    f = cleft*ibuf_copy[3] + cown*ibuf_copy[2];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[2] = f;
                    f = cleft*ibuf_copy[1] + cown*ibuf_copy[3];
                    SOX_SAMPLE_CLIP_COUNT(f, effp->clips);
                    obuf[3] = f;
                    obuf += 4;
                    ibuf_copy += 4;
                }
            }
            break;
        default:
            UNEXPECTED_CHANNELS;
            break;
        } /* end third switch in channel */
        break;
    default:
        UNEXPECTED_CHANNELS;
        break;
    } /* end switch out channel */

    free(ibuf_copy - len * ich);

    return SOX_SUCCESS;
}