예제 #1
0
파일: formats.c 프로젝트: dmkrepo/libsox
static FILE * xfopen(char const * identifier, char const * mode, lsx_io_type * io_type)
{
  *io_type = lsx_io_file;

  if (*identifier == '|') {
    FILE * f = NULL;
#ifdef HAVE_POPEN
#ifndef POPEN_MODE
#define POPEN_MODE "r"
#endif
    f = popen(identifier + 1, POPEN_MODE);
    *io_type = lsx_io_pipe;
#else
    lsx_fail("this build of SoX cannot open pipes");
#endif
    return f;
  }
  else if (is_url(identifier)) {
    FILE * f = NULL;
#ifdef HAVE_POPEN
    char const * const command_format = "wget --no-check-certificate -q -O- \"%s\"";
    char * command = lsx_malloc(strlen(command_format) + strlen(identifier));
    sprintf(command, command_format, identifier);
    f = popen(command, POPEN_MODE);
    free(command);
    *io_type = lsx_io_url;
#else
    lsx_fail("this build of SoX cannot open URLs");
#endif
    return f;
  }
  return fopen(identifier, mode);
}
예제 #2
0
파일: reverse.c 프로젝트: Emisense/eTracks
static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp)
{
  priv_t * p = (priv_t *)effp->priv;
  size_t i, j;

  if (p->pos == 0) {
    fflush(p->tmp_file);
    p->pos = ftello(p->tmp_file);
    if (p->pos % sizeof(sox_sample_t) != 0) {
      lsx_fail("temporary file has incorrect size");
      return SOX_EOF;
    }
    p->pos /= sizeof(sox_sample_t);
  }
  p->pos -= *osamp = min((off_t)*osamp, p->pos);
  fseeko(p->tmp_file, (off_t)(p->pos * sizeof(sox_sample_t)), SEEK_SET);
  if (fread(obuf, sizeof(sox_sample_t), *osamp, p->tmp_file) != *osamp) {
    lsx_fail("error reading temporary file: %s", strerror(errno));
    return SOX_EOF;
  }
  for (i = 0, j = *osamp - 1; i < j; ++i, --j) { /* reverse the samples */
    sox_sample_t temp = obuf[i];
    obuf[i] = obuf[j];
    obuf[j] = temp;
  }
  return p->pos? SOX_SUCCESS : SOX_EOF;
}
예제 #3
0
static int startread(sox_format_t * ft)
{
  priv_t * ffmpeg = (priv_t *)ft->priv;
  AVFormatParameters params;
  int ret;
  int i;

  ffmpeg->audio_buf_raw = lsx_calloc(1, (size_t)AVCODEC_MAX_AUDIO_FRAME_SIZE + 32);
  ffmpeg->audio_buf_aligned = ALIGN16(ffmpeg->audio_buf_raw);

  /* Signal audio stream not found */
  ffmpeg->audio_index = -1;

  /* register all CODECs, demux and protocols */
  av_register_all();

  /* Open file and get format */
  memset(&params, 0, sizeof(params));
  if ((ret = av_open_input_file(&ffmpeg->ctxt, ft->filename, NULL, 0, &params)) < 0) {
    lsx_fail("ffmpeg cannot open file for reading: %s (code %d)", ft->filename, ret);
    return SOX_EOF;
  }

  /* Get CODEC parameters */
  if ((ret = av_find_stream_info(ffmpeg->ctxt)) < 0) {
    lsx_fail("ffmpeg could not find CODEC parameters for %s", ft->filename);
    return SOX_EOF;
  }

  /* Now we can begin to play (RTSP stream only) */
  av_read_play(ffmpeg->ctxt);

  /* Find audio stream (FIXME: allow different stream to be selected) */
  for (i = 0; (unsigned)i < ffmpeg->ctxt->nb_streams; i++) {
    AVCodecContext *enc = ffmpeg->ctxt->streams[i]->codec;
    if (enc->codec_type == CODEC_TYPE_AUDIO && ffmpeg->audio_index < 0) {
      ffmpeg->audio_index = i;
      break;
    }
  }

  /* Open the stream */
  if (ffmpeg->audio_index < 0 ||
      stream_component_open(ffmpeg, ffmpeg->audio_index) < 0 ||
      ffmpeg->audio_stream < 0) {
    lsx_fail("ffmpeg could not open CODECs for %s", ft->filename);
    return SOX_EOF;
  }

  /* Copy format info */
  ft->signal.rate = ffmpeg->audio_st->codec->sample_rate;
  ft->encoding.bits_per_sample = 16;
  ft->encoding.encoding = SOX_ENCODING_SIGN2;
  ft->signal.channels = ffmpeg->audio_st->codec->channels;
  ft->signal.length = 0; /* Currently we can't seek; no idea how to get this
		     info from ffmpeg anyway (in time, yes, but not in
		     samples); but ffmpeg *can* seek */

  return SOX_SUCCESS;
}
예제 #4
0
파일: pad.c 프로젝트: damien78/sox
static int start(sox_effect_t * effp)
{
  priv_t * p = (priv_t *)effp->priv;
  unsigned i;

  /* Re-parse now rate is known */
  if (parse(effp, 0, effp->in_signal.rate) != SOX_SUCCESS)
    return SOX_EOF;

  if ((effp->out_signal.length = effp->in_signal.length) != SOX_UNKNOWN_LEN) {
    for (i = 0; i < p->npads; ++i)
      effp->out_signal.length +=
        p->pads[i].pad * effp->in_signal.channels;

    /* Check that the last pad position (except for "at the end")
       is within bounds. */
    i = p->npads;
    if (i > 0 && p->pads[i-1].start == UINT64_MAX)
      i--;
    if (i > 0 &&
        p->pads[i-1].start * effp->in_signal.channels
          > effp->in_signal.length)
    {
      lsx_fail("pad position after end of audio");
      return SOX_EOF;
    }
  }

  p->in_pos = p->out_pos = p->pad_pos = p->pads_pos = 0;
  for (i = 0; i < p->npads; ++i)
    if (p->pads[i].pad || p->pads[i].align)
      return SOX_SUCCESS;
  return SOX_EFF_NULL;
}
예제 #5
0
파일: echo.c 프로젝트: 5in4/libsox.dll
/*
 * Process options
 */
static int sox_echo_getopts(sox_effect_t * effp, int argc, char **argv)
{
        priv_t * echo = (priv_t *) effp->priv;
        int i;

  --argc, ++argv;
        echo->num_delays = 0;

        if ((argc < 4) || (argc % 2))
          return lsx_usage(effp);

        i = 0;
        sscanf(argv[i++], "%f", &echo->in_gain);
        sscanf(argv[i++], "%f", &echo->out_gain);
        while (i < argc) {
                if ( echo->num_delays >= MAX_ECHOS )
                        lsx_fail("echo: to many delays, use less than %i delays",
                                MAX_ECHOS);
                /* Linux bug and it's cleaner. */
                sscanf(argv[i++], "%f", &echo->delay[echo->num_delays]);
                sscanf(argv[i++], "%f", &echo->decay[echo->num_delays]);
                echo->num_delays++;
        }
        return (SOX_SUCCESS);
}
예제 #6
0
파일: mcompand.c 프로젝트: DeathOfMe/sox
static int parse_subarg(char *s, char **subargv, size_t *subargc) {
  char **ap;
  char *s_p;

  s_p = s;
  *subargc = 0;
  for (ap = subargv; (*ap = strtok(s_p, " \t")) != NULL;) {
    s_p = NULL;
    if (*subargc == 5) {
      ++*subargc;
      break;
    }
    if (**ap != '\0') {
      ++ap;
      ++*subargc;
    }
  }

  if (*subargc < 2 || *subargc > 5)
    {
      lsx_fail("Wrong number of parameters for the compander effect within mcompand; usage:\n"
  "\tattack1,decay1{,attack2,decay2} [soft-knee-dB:]in-dB1[,out-dB1]{,in-dB2,out-dB2} [gain [initial-volume-dB [delay]]]\n"
  "\twhere {} means optional and repeatable and [] means optional.\n"
  "\tdB values are floating point or -inf'; times are in seconds.");
      return (SOX_EOF);
    } else
      return SOX_SUCCESS;
}
예제 #7
0
파일: bend.c 프로젝트: CaptainHayashi/sox
static int parse(sox_effect_t * effp, char **argv, sox_rate_t rate)
{
  priv_t *p = (priv_t *) effp->priv;
  size_t i;
  char const *next;
  uint64_t last_seen = 0;
  const uint64_t in_length = argv ? 0 :
    (effp->in_signal.length != SOX_UNKNOWN_LEN ?
     effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN);

  for (i = 0; i < p->nbends; ++i) {
    if (argv)   /* 1st parse only */
      p->bends[i].str = lsx_strdup(argv[i]);

    next = lsx_parseposition(rate, p->bends[i].str,
             argv ? NULL : &p->bends[i].start, last_seen, in_length, '+');
    last_seen = p->bends[i].start;
    if (next == NULL || *next != ',')
      break;

    p->bends[i].cents = strtod(next + 1, (char **)&next);
    if (p->bends[i].cents == 0 || *next != ',')
      break;

    next = lsx_parseposition(rate, next + 1,
             argv ? NULL : &p->bends[i].duration, last_seen, in_length, '+');
    last_seen = p->bends[i].duration;
    if (next == NULL || *next != '\0')
      break;

    /* sanity checks */
    if (!argv && p->bends[i].duration < p->bends[i].start) {
      lsx_fail("Bend %" PRIuPTR " has negative width", i+1);
      break;
    }
    if (!argv && i && p->bends[i].start < p->bends[i-1].start) {
      lsx_fail("Bend %" PRIuPTR " overlaps with previous one", i+1);
      break;
    }

    p->bends[i].duration -= p->bends[i].start;
  }
  if (i < p->nbends)
    return lsx_usage(effp);
  return SOX_SUCCESS;
}
예제 #8
0
static int getopts(sox_effect_t * effp, int argc, char **argv)
{
  char *subargv[6], *cp;
  size_t subargc, i, len;

  priv_t * c = (priv_t *) effp->priv;
  --argc, ++argv;

  c->band_buf1 = c->band_buf2 = c->band_buf3 = 0;
  c->band_buf_len = 0;

  /* how many bands? */
  if (! (argc&1)) {
    lsx_fail("mcompand accepts only an odd number of arguments:\argc"
            "  mcompand quoted_compand_args [crossover_freq quoted_compand_args [...]");
    return SOX_EOF;
  }
  c->nBands = (argc+1)>>1;

  c->bands = lsx_calloc(c->nBands, sizeof(comp_band_t));

  for (i=0;i<c->nBands;++i) {
    len = strlen(argv[i<<1]);
    if (parse_subarg(argv[i<<1],subargv,&subargc) != SOX_SUCCESS)
      return SOX_EOF;
    if (sox_mcompand_getopts_1(&c->bands[i], subargc, &subargv[0]) != SOX_SUCCESS)
      return SOX_EOF;
    if (i == (c->nBands-1))
      c->bands[i].topfreq = 0;
    else {
      c->bands[i].topfreq = lsx_parse_frequency(argv[(i<<1)+1],&cp);
      if (*cp) {
        lsx_fail("bad frequency in args to mcompand");
        return SOX_EOF;
      }
      if ((i>0) && (c->bands[i].topfreq < c->bands[i-1].topfreq)) {
        lsx_fail("mcompand crossover frequencies must be in ascending order.");
        return SOX_EOF;
      }
    }
  }

  return SOX_SUCCESS;
}
예제 #9
0
파일: crop.c 프로젝트: Amalerd/SoxPlayer
static int start(sox_effect_t * effp)
{
  priv_t * p = (priv_t *)effp->priv;
  int i;

  p->pos[1].at = SIZE_MAX / 2 / effp->in_signal.channels;
  parse(effp, 0, effp->in_signal.rate); /* Re-parse now rate is known */
  for (i = 0; i < 2; ++i) {
    p->pos[i].at *= effp->in_signal.channels;
    if (p->pos[i].flag == '-') {
      if (effp->in_signal.length == SOX_UNSPEC) {
        lsx_fail("cannot crop from end: audio length is not known");
        return SOX_EOF;
      }
      if (p->pos[i].at > effp->in_signal.length) {
        lsx_fail("cannot crop that much from end: audio is too short");
        return SOX_EOF;
      }
      p->pos[i].at = effp->in_signal.length - p->pos[i].at;
    }
  }
  if (p->pos[1].flag != '+') {
    if (p->pos[0].at > p->pos[1].at) {
      lsx_fail("start position must be less than stop position");
      return SOX_EOF;
    }
    if (!(p->pos[1].at -= p->pos[0].at))
      p->pos[0].at = 0;
  }
  if (effp->in_signal.length) {
    if (!p->pos[0].at && p->pos[1].at == effp->in_signal.length)
      return SOX_EFF_NULL;
    if (p->pos[0].at > effp->in_signal.length ||
        (p->argc > 1 && p->pos[0].at + p->pos[1].at > effp->in_signal.length)) {
      lsx_fail("audio is too short");
      return SOX_EOF;
    }
    effp->out_signal.length = p->argc == 2 ?
      p->pos[1].at : effp->in_signal.length - p->pos[0].at;
  }
  return SOX_SUCCESS;
}
예제 #10
0
파일: reverse.c 프로젝트: Emisense/eTracks
static int start(sox_effect_t * effp)
{
  priv_t * p = (priv_t *)effp->priv;
  p->pos = 0;
  p->tmp_file = tmpfile();
  if (p->tmp_file == NULL) {
    lsx_fail("can't create temporary file: %s", strerror(errno));
    return SOX_EOF;
  }
  return SOX_SUCCESS;
}
예제 #11
0
파일: reverse.c 프로젝트: Emisense/eTracks
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
    sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
  priv_t * p = (priv_t *)effp->priv;
  if (fwrite(ibuf, sizeof(*ibuf), *isamp, p->tmp_file) != *isamp) {
    lsx_fail("error writing temporary file: %s", strerror(errno));
    return SOX_EOF;
  }
  (void)obuf, *osamp = 0; /* samples not output until drain */
  return SOX_SUCCESS;
}
예제 #12
0
파일: mixer.c 프로젝트: Amalerd/SoxPlayer
/*
 * Process options
 */
static int getopts(sox_effect_t * effp, int argc, char **argv)
{
    priv_t * mixer = (priv_t *) effp->priv;
    double* pans = &mixer->sources[0][0];
    int i;
  --argc, ++argv;

    for (i = 0;  i < 16;  i++)
        pans[i] = 0.0;
    mixer->mix = MIX_CENTER;
    mixer->num_pans = 0;

    /* Parse parameters.  Since we don't yet know the number of */
    /* input and output channels, we'll record the information for */
    /* later. */
    if (argc == 1) {
        if      (!strcmp(argv[0], "-l")) mixer->mix = 'l';
        else if (!strcmp(argv[0], "-r")) mixer->mix = 'r';
        else if (!strcmp(argv[0], "-f")) mixer->mix = 'f';
        else if (!strcmp(argv[0], "-b")) mixer->mix = 'b';
        else if (!strcmp(argv[0], "-1")) mixer->mix = '1';
        else if (!strcmp(argv[0], "-2")) mixer->mix = '2';
        else if (!strcmp(argv[0], "-3")) mixer->mix = '3';
        else if (!strcmp(argv[0], "-4")) mixer->mix = '4';
        else if (argv[0][0] == '-' && !isdigit((int)argv[0][1])
                && argv[0][1] != '.')
          return lsx_usage(effp);
        else {
            int commas;
            char *s;
            mixer->mix = MIX_SPECIFIED;
            pans[0] = atof(argv[0]);
            for (s = argv[0], commas = 0; *s; ++s) {
                if (*s == ',') {
                    ++commas;
                    if (commas >= 16) {
                        lsx_fail("mixer can only take up to 16 pan values");
                        return (SOX_EOF);
                    }
                    pans[commas] = atof(s+1);
                }
            }
            mixer->num_pans = commas + 1;
        }
    }
    else if (argc == 0) {
        mixer->mix = MIX_CENTER;
    }
    else
      return lsx_usage(effp);

    return (SOX_SUCCESS);
}
예제 #13
0
파일: repeat.c 프로젝트: Emisense/eTracks
static int start(sox_effect_t * effp)
{
  priv_t * p = (priv_t *)effp->priv;
  if (p->repeats == 0)
    return SOX_EFF_NULL;

  if ((p->tmp_file = tmpfile()) == NULL) {
    lsx_fail("can't create temporary file: %s", strerror(errno));
    return SOX_EOF;
  }
  p->first_drain = 1;
  return SOX_SUCCESS;
}
예제 #14
0
파일: dop.c 프로젝트: mutagene/sox
static int dop_start(sox_effect_t *eff)
{
  dop_t *p = eff->priv;

  if (eff->in_signal.precision != 1) {
    lsx_fail("1-bit input required");
    return SOX_EOF;
  }

  if (eff->in_signal.rate != 16 * eff->out_signal.rate) {
    lsx_fail("incorrect output rate, should be %.1fk",
             eff->in_signal.rate / 16 / 1000);
    return SOX_EOF;
  }

  eff->out_signal.precision = 24;

  p->buf = lsx_calloc(eff->out_signal.channels, sizeof(*p->buf));
  p->marker = DOP_MARKER;

  return SOX_SUCCESS;
}
예제 #15
0
static int open_audio(priv_t * ffmpeg, AVStream *st)
{
  AVCodecContext *c;
  AVCodec *codec;

  c = st->codec;

  /* find the audio encoder */
  codec = avcodec_find_encoder(c->codec_id);
  if (!codec) {
    lsx_fail("ffmpeg CODEC not found");
    return SOX_EOF;
  }

  /* open it */
  if (avcodec_open(c, codec) < 0) {
    lsx_fail("ffmpeg could not open CODEC");
    return SOX_EOF;
  }

  ffmpeg->audio_buf_raw = lsx_malloc((size_t)AVCODEC_MAX_AUDIO_FRAME_SIZE + 32);
  ffmpeg->audio_buf_aligned = ALIGN16(ffmpeg->audio_buf_raw);

  /* ugly hack for PCM codecs (will be removed ASAP with new PCM
     support to compute the input frame size in samples */
  if (c->frame_size <= 1) {
    ffmpeg->audio_input_frame_size = AVCODEC_MAX_AUDIO_FRAME_SIZE / c->channels;
    switch(st->codec->codec_id) {
    case CODEC_ID_PCM_S16LE:
    case CODEC_ID_PCM_S16BE:
    case CODEC_ID_PCM_U16LE:
    case CODEC_ID_PCM_U16BE:
      ffmpeg->audio_input_frame_size >>= 1;
      break;
    default:
      break;
    }
  } else
예제 #16
0
파일: mcompand.c 프로젝트: DeathOfMe/sox
/*
 * Process options
 *
 * Don't do initialization now.
 * The 'info' fields are not yet filled in.
 */
static int sox_mcompand_getopts_1(comp_band_t * l, size_t n, char **argv)
{
      char *s;
      size_t rates, i, commas;

      /* Start by checking the attack and decay rates */

      for (s = argv[0], commas = 0; *s; ++s)
        if (*s == ',') ++commas;

      if (commas % 2 == 0) /* There must be an even number of
                              attack/decay parameters */
      {
        lsx_fail("compander: Odd number of attack & decay rate parameters");
        return (SOX_EOF);
      }

      rates = 1 + commas/2;
      l->attackRate = lsx_malloc(sizeof(double) * rates);
      l->decayRate  = lsx_malloc(sizeof(double) * rates);
      l->volume = lsx_malloc(sizeof(double) * rates);
      l->expectedChannels = rates;
      l->delay_buf = NULL;

      /* Now tokenise the rates string and set up these arrays.  Keep
         them in seconds at the moment: we don't know the sample rate yet. */

      s = strtok(argv[0], ","); i = 0;
      do {
        l->attackRate[i] = atof(s); s = strtok(NULL, ",");
        l->decayRate[i]  = atof(s); s = strtok(NULL, ",");
        ++i;
      } while (s != NULL);

      if (!lsx_compandt_parse(&l->transfer_fn, argv[1], n>2 ? argv[2] : 0))
        return SOX_EOF;

      /* Set the initial "volume" to be attibuted to the input channels.
         Unless specified, choose 1.0 (maximum) otherwise clipping will
         result if the user has seleced a long attack time */
      for (i = 0; i < l->expectedChannels; ++i) {
        double v = n>=4 ? pow(10.0, atof(argv[3])/20) : 1.0;
        l->volume[i] = v;

        /* If there is a delay, store it. */
        if (n >= 5) l->delay = atof(argv[4]);
        else l->delay = 0.0;
      }
    return (SOX_SUCCESS);
}
예제 #17
0
static int startwrite(sox_format_t * ft)
{
  priv_t * sf = (priv_t *)ft->priv;
  start(ft);
  /* If output format is invalid, try to find a sensible default */
  if (!sf_format_check(sf->sf_info)) {
    SF_FORMAT_INFO format_info;
    int i, count;

    sf_command(sf->sf_file, SFC_GET_SIMPLE_FORMAT_COUNT, &count, (int) sizeof(int));
    for (i = 0; i < count; i++) {
      format_info.format = i;
      sf_command(sf->sf_file, SFC_GET_SIMPLE_FORMAT, &format_info, (int) sizeof(format_info));
      if ((format_info.format & SF_FORMAT_TYPEMASK) == (sf->sf_info->format & SF_FORMAT_TYPEMASK)) {
        sf->sf_info->format = format_info.format;
        /* FIXME: Print out exactly what we chose, needs sndfile ->
           sox encoding conversion functions */
        break;
      }
    }

    if (!sf_format_check(sf->sf_info)) {
      lsx_fail("cannot find a usable output encoding");
      return SOX_EOF;
    }
    if ((sf->sf_info->format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW)
      lsx_warn("cannot use desired output encoding, choosing default");
  }

  sf->sf_file = sf_open_fd(fileno(ft->fp), SFM_WRITE, sf->sf_info, 1);
  ft->fp = NULL; /* Transfer ownership of fp to LSF */
  drain_log_buffer(ft);

  if (sf->sf_file == NULL) {
    memset(ft->sox_errstr, 0, sizeof(ft->sox_errstr));
    strncpy(ft->sox_errstr, sf_strerror(sf->sf_file), sizeof(ft->sox_errstr)-1);
    free(sf->sf_file);
    return SOX_EOF;
  }

#ifdef HAVE_SFC_SET_SCALE_INT_FLOAT_WRITE
  if ((sf->sf_info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT)
    sf_command(sf->sf_file, SFC_SET_SCALE_INT_FLOAT_WRITE, NULL, SF_TRUE);
#endif
           
  return SOX_SUCCESS;
}
예제 #18
0
파일: util.c 프로젝트: Amalerd/SoxPlayer
int lsx_enum_option(int c, lsx_enum_item const * items)
{
  lsx_enum_item const * p = lsx_find_enum_text(lsx_optarg, items, sox_false);
  if (p == NULL) {
    size_t len = 1;
    char * set = lsx_malloc(len);
    *set = 0;
    for (p = items; p->text; ++p) {
      set = lsx_realloc(set, len += 2 + strlen(p->text));
      strcat(set, ", "); strcat(set, p->text);
    }
    lsx_fail("-%c: `%s' is not one of: %s.", c, lsx_optarg, set + 2);
    free(set);
    return INT_MAX;
  }
  return p->value;
}
예제 #19
0
파일: stats.c 프로젝트: Amalerd/SoxPlayer
static int getopts(sox_effect_t * effp, int argc, char **argv)
{
  priv_t * p = (priv_t *)effp->priv;
  int c;

  p->time_constant = .05;
  p->scale = 1;
  while ((c = lsx_getopt(argc, argv, "+x:b:w:s:")) != -1) switch (c) {
    GETOPT_NUMERIC('x', hex_bits      ,  2 , 32)
    GETOPT_NUMERIC('b', scale_bits    ,  2 , 32)
    GETOPT_NUMERIC('w', time_constant ,  .01 , 10)
    GETOPT_NUMERIC('s', scale         ,  -99, 99)
    default: lsx_fail("invalid option `-%c'", optopt); return lsx_usage(effp);
  }
  if (p->hex_bits)
    p->scale_bits = p->hex_bits;
  return lsx_optind != argc? lsx_usage(effp) : SOX_SUCCESS;
}
예제 #20
0
파일: sinc.c 프로젝트: Amalerd/SoxPlayer
static int start(sox_effect_t * effp)
{
  priv_t * p = (priv_t *)effp->priv;
  dft_filter_t * f = p->base.filter_ptr;

  if (!f->num_taps) {
    double Fn = effp->in_signal.rate * .5;
    double * h[2];
    int i, n, post_peak, longer;

    if (p->Fc0 >= Fn || p->Fc1 >= Fn) {
      lsx_fail("filter frequency must be less than sample-rate / 2");
      return SOX_EOF;
    }
    h[0] = lpf(Fn, p->Fc0, p->tbw0, &p->num_taps[0], p->att, &p->beta,p->round);
    h[1] = lpf(Fn, p->Fc1, p->tbw1, &p->num_taps[1], p->att, &p->beta,p->round);
    if (h[0])
      invert(h[0], p->num_taps[0]);

    longer = p->num_taps[1] > p->num_taps[0];
    n = p->num_taps[longer];
    if (h[0] && h[1]) {
      for (i = 0; i < p->num_taps[!longer]; ++i)
        h[longer][i + (n - p->num_taps[!longer])/2] += h[!longer][i];

      if (p->Fc0 < p->Fc1)
        invert(h[longer], n);

      free(h[!longer]);
    }
    if (p->phase != 50)
      lsx_fir_to_phase(&h[longer], &n, &post_peak, p->phase);
    else post_peak = n >> 1;

    if (effp->global_info->plot != sox_plot_off) {
      char title[100];
      sprintf(title, "SoX effect: sinc filter freq=%g-%g",
          p->Fc0, p->Fc1? p->Fc1 : Fn);
      lsx_plot_fir(h[longer], n, effp->in_signal.rate,
          effp->global_info->plot, title, -p->beta * 10 - 25, 5.);
      return SOX_EOF;
    }
    lsx_set_dft_filter(f, h[longer], n, post_peak);
  }
예제 #21
0
파일: input.c 프로젝트: Emisense/eTracks
static int drain(
    sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp)
{
  priv_t * p = (priv_t *)effp->priv;

  /* ensure that *osamp is a multiple of the number of channels. */
  *osamp -= *osamp % effp->out_signal.channels;

  /* Read up to *osamp samples into obuf; store the actual number read
   * back to *osamp */
  *osamp = sox_read(p->file, obuf, *osamp);

  /* sox_read may return a number that is less than was requested; only if
   * 0 samples is returned does it indicate that end-of-file has been reached
   * or an error has occurred */
  if (!*osamp && p->file->sox_errno)
    lsx_fail("%s: %s", p->file->filename, p->file->sox_errstr);
  return *osamp? SOX_SUCCESS : SOX_EOF;
}
예제 #22
0
파일: bend.c 프로젝트: CaptainHayashi/sox
static int create(sox_effect_t * effp, int argc, char **argv)
{
  priv_t *p = (priv_t *) effp->priv;
  char const * opts = "f:o:";
  int c;
  lsx_getopt_t optstate;
  lsx_getopt_init(argc, argv, opts, NULL, lsx_getopt_flag_none, 1, &optstate);

  p->frame_rate = 25;
  p->ovsamp = 16;
  while ((c = lsx_getopt(&optstate)) != -1) switch (c) {
    GETOPT_NUMERIC(optstate, 'f', frame_rate, 10 , 80)
    GETOPT_NUMERIC(optstate, 'o', ovsamp,  4 , 32)
    default: lsx_fail("unknown option `-%c'", optstate.opt); return lsx_usage(effp);
  }
  argc -= optstate.ind, argv += optstate.ind;

  p->nbends = argc;
  p->bends = lsx_calloc(p->nbends, sizeof(*p->bends));
  return parse(effp, argv, 0.);     /* No rate yet; parse with dummy */
}
예제 #23
0
파일: ffmpeg.c 프로젝트: Emisense/eTracks
/* open a given stream. Return 0 if OK */
static int stream_component_open(priv_t * ffmpeg, int stream_index)
{
  AVFormatContext *ic = ffmpeg->ctxt;
  AVCodecContext *enc;
  AVCodec *codec;

  if (stream_index < 0 || stream_index >= (int)(ic->nb_streams))
    return -1;
  enc = ic->streams[stream_index]->codec;

  /* hack for AC3. XXX: suppress that */
  if (enc->channels > 2)
    enc->channels = 2;

  codec = avcodec_find_decoder(enc->codec_id);
  enc->workaround_bugs = 1;
#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0)
  enc->error_resilience = 1;
#else
  enc->error_recognition = 1;
#endif

  if (!codec || avcodec_open(enc, codec) < 0)
    return -1;
  if (enc->codec_type != CODEC_TYPE_AUDIO) {
    lsx_fail("ffmpeg CODEC %x is not an audio CODEC", enc->codec_type);
    return -1;
  }

  ffmpeg->audio_stream = stream_index;
  ffmpeg->audio_st = ic->streams[stream_index];
  ffmpeg->audio_buf_size = 0;
  ffmpeg->audio_buf_index = 0;

  memset(&ffmpeg->audio_pkt, 0, sizeof(ffmpeg->audio_pkt));

  return 0;
}
예제 #24
0
파일: ffmpeg.c 프로젝트: Emisense/eTracks
/*
 * add an audio output stream
 */
static AVStream *add_audio_stream(sox_format_t * ft, AVFormatContext *oc, enum CodecID codec_id)
{
  AVCodecContext *c;
  AVStream *st;

  st = av_new_stream(oc, 1);
  if (!st) {
    lsx_fail("ffmpeg could not alloc stream");
    return NULL;
  }

  c = st->codec;
  c->codec_id = codec_id;
  c->codec_type = CODEC_TYPE_AUDIO;

  /* put sample parameters */
  c->bit_rate = 256000;  /* FIXME: allow specification */
  /* FIXME: currently mplayer says files do not have a specified
     compressed bit-rate */
  c->sample_rate = ft->signal.rate;
  c->channels = ft->signal.channels;
  return st;
}
예제 #25
0
파일: rabbit.c 프로젝트: Emisense/eTracks
/*
 * Prepare processing.
 */
static int start(sox_effect_t * effp)
{
  priv_t * r = (priv_t *) effp->priv;
  int err = 0;
  double out_rate = r->out_rate != HUGE_VAL? r->out_rate : effp->out_signal.rate;

  if (effp->in_signal.rate == out_rate)
    return SOX_EFF_NULL;

  effp->out_signal.channels = effp->in_signal.channels;
  effp->out_signal.rate = out_rate;

  r->data = lsx_calloc(1, sizeof(SRC_DATA));
  r->data->src_ratio = out_rate / effp->in_signal.rate;
  r->i_alloc = r->o_alloc = 0;
  r->state = src_new(r->converter_type, (int)effp->in_signal.channels, &err);
  if (err) {
    free(r->data);
    lsx_fail("cannot initialise rabbit: %s", src_strerror(err));
    return SOX_EOF;
  }

  return SOX_SUCCESS;
}
예제 #26
0
파일: echo.c 프로젝트: 5in4/libsox.dll
/*
 * Prepare for processing.
 */
static int sox_echo_start(sox_effect_t * effp)
{
        priv_t * echo = (priv_t *) effp->priv;
        int i;
        float sum_in_volume;
        long j;

        echo->maxsamples = 0;
        if ( echo->in_gain < 0.0 )
        {
                lsx_fail("echo: gain-in must be positive!");
                return (SOX_EOF);
        }
        if ( echo->in_gain > 1.0 )
        {
                lsx_fail("echo: gain-in must be less than 1.0!");
                return (SOX_EOF);
        }
        if ( echo->out_gain < 0.0 )
        {
                lsx_fail("echo: gain-in must be positive!");
                return (SOX_EOF);
        }
        for ( i = 0; i < echo->num_delays; i++ ) {
                echo->samples[i] = echo->delay[i] * effp->in_signal.rate / 1000.0;
                if ( echo->samples[i] < 1 )
                {
                    lsx_fail("echo: delay must be positive!");
                    return (SOX_EOF);
                }
                if ( echo->samples[i] > (ptrdiff_t)DELAY_BUFSIZ )
                {
                        lsx_fail("echo: delay must be less than %g seconds!",
                                DELAY_BUFSIZ / effp->in_signal.rate );
                        return (SOX_EOF);
                }
                if ( echo->decay[i] < 0.0 )
                {
                    lsx_fail("echo: decay must be positive!" );
                    return (SOX_EOF);
                }
                if ( echo->decay[i] > 1.0 )
                {
                    lsx_fail("echo: decay must be less than 1.0!" );
                    return (SOX_EOF);
                }
                if ( echo->samples[i] > echo->maxsamples )
                        echo->maxsamples = echo->samples[i];
        }
        echo->delay_buf = lsx_malloc(sizeof (double) * echo->maxsamples);
        for ( j = 0; j < echo->maxsamples; ++j )
                echo->delay_buf[j] = 0.0;
        /* Be nice and check the hint with warning, if... */
        sum_in_volume = 1.0;
        for ( i = 0; i < echo->num_delays; i++ )
                sum_in_volume += echo->decay[i];
        if ( sum_in_volume * echo->in_gain > 1.0 / echo->out_gain )
                lsx_warn("echo: warning >>> gain-out can cause saturation of output <<<");
        echo->counter = 0;
        echo->fade_out = echo->maxsamples;

  effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */

        return (SOX_SUCCESS);
}
예제 #27
0
파일: compand.c 프로젝트: Amalerd/SoxPlayer
static int getopts(sox_effect_t * effp, int argc, char * * argv)
{
  priv_t * l = (priv_t *) effp->priv;
  char * s;
  char dummy;     /* To check for extraneous chars. */
  unsigned pairs, i, j, commas;

  --argc, ++argv;
  if (argc < 2 || argc > 5)
    return lsx_usage(effp);

  /* Start by checking the attack and decay rates */
  for (s = argv[0], commas = 0; *s; ++s) if (*s == ',') ++commas;
  if ((commas % 2) == 0) {
    lsx_fail("there must be an even number of attack/decay parameters");
    return SOX_EOF;
  }
  pairs = 1 + commas/2;
  l->channels = lsx_calloc(pairs, sizeof(*l->channels));
  l->expectedChannels = pairs;

  /* Now tokenise the rates string and set up these arrays.  Keep
     them in seconds at the moment: we don't know the sample rate yet. */
  for (i = 0, s = strtok(argv[0], ","); s != NULL; ++i) {
    for (j = 0; j < 2; ++j) {
      if (sscanf(s, "%lf %c", &l->channels[i].attack_times[j], &dummy) != 1) {
        lsx_fail("syntax error trying to read attack/decay time");
        return SOX_EOF;
      } else if (l->channels[i].attack_times[j] < 0) {
        lsx_fail("attack & decay times can't be less than 0 seconds");
        return SOX_EOF;
      }
      s = strtok(NULL, ",");
    }
  }

  if (!lsx_compandt_parse(&l->transfer_fn, argv[1], argc>2 ? argv[2] : 0))
    return SOX_EOF;

  /* Set the initial "volume" to be attibuted to the input channels.
     Unless specified, choose 0dB otherwise clipping will
     result if the user has seleced a long attack time */
  for (i = 0; i < l->expectedChannels; ++i) {
    double init_vol_dB = 0;
    if (argc > 3 && sscanf(argv[3], "%lf %c", &init_vol_dB, &dummy) != 1) {
      lsx_fail("syntax error trying to read initial volume");
      return SOX_EOF;
    } else if (init_vol_dB > 0) {
      lsx_fail("initial volume is relative to maximum volume so can't exceed 0dB");
      return SOX_EOF;
    }
    l->channels[i].volume = pow(10., init_vol_dB / 20);
  }

  /* If there is a delay, store it. */
  if (argc > 4 && sscanf(argv[4], "%lf %c", &l->delay, &dummy) != 1) {
    lsx_fail("syntax error trying to read delay value");
    return SOX_EOF;
  } else if (l->delay < 0) {
    lsx_fail("delay can't be less than 0 seconds");
    return SOX_EOF;
  }

  return SOX_SUCCESS;
}
예제 #28
0
sox_format_t * sox_open_read(
    char               const * path,
    sox_signalinfo_t   const * signal,
    sox_encodinginfo_t const * encoding,
    char               const * filetype)
{
  sox_format_t * ft = lsx_calloc(1, sizeof(*ft));
  sox_format_handler_t const * handler;
  char const * const io_types[] = {"file", "pipe", "file URL"};
  char const * type = "";
  size_t   input_bufsiz = sox_globals.input_bufsiz?
      sox_globals.input_bufsiz : sox_globals.bufsiz;

  if (filetype) {
    if (!(handler = sox_find_format(filetype, sox_false))) {
      lsx_fail("no handler for given file type `%s'", filetype);
      goto error;
    }
    ft->handler = *handler;
  }

  if (!(ft->handler.flags & SOX_FILE_NOSTDIO)) {
    if (!strcmp(path, "-")) { /* Use stdin if the filename is "-" */
      if (sox_globals.stdin_in_use_by) {
        lsx_fail("`-' (stdin) already in use by `%s'", sox_globals.stdin_in_use_by);
        goto error;
      }
      sox_globals.stdin_in_use_by = "audio input";
      SET_BINARY_MODE(stdin);
      ft->fp = stdin;
    }
    else {
      ft->fp = xfopen(path, "rb", &ft->io_type);
      type = io_types[ft->io_type];
      if (ft->fp == NULL) {
        lsx_fail("can't open input %s `%s': %s", type, path, strerror(errno));
        goto error;
      }
    }
    if (setvbuf (ft->fp, NULL, _IOFBF, sizeof(char) * input_bufsiz)) {
      lsx_fail("Can't set read buffer");
      goto error;
    }
    ft->seekable = is_seekable(ft);
  }

  if (!filetype) {
    if (ft->seekable) {
      filetype = auto_detect_format(ft, lsx_find_file_extension(path));
      lsx_rewind(ft);
    }
#ifndef NO_REWIND_PIPE
    else if (!(ft->handler.flags & SOX_FILE_NOSTDIO) &&
        input_bufsiz >= AUTO_DETECT_SIZE) {
      filetype = auto_detect_format(ft, lsx_find_file_extension(path));
      rewind_pipe(ft->fp);
      ft->tell_off = 0;
    }
#endif

    if (filetype) {
      lsx_report("detected file format type `%s'", filetype);
      if (!(handler = sox_find_format(filetype, sox_false))) {
        lsx_fail("no handler for detected file type `%s'", filetype);
        goto error;
      }
    }
    else {
      if (ft->io_type == lsx_io_pipe) {
        filetype = "sox"; /* With successful pipe rewind, this isn't useful */
        lsx_report("assuming input pipe `%s' has file-type `sox'", path);
      }
      else if (!(filetype = lsx_find_file_extension(path))) {
        lsx_fail("can't determine type of %s `%s'", type, path);
        goto error;
      }
      if (!(handler = sox_find_format(filetype, sox_true))) {
        lsx_fail("no handler for file extension `%s'", filetype);
        goto error;
      }
    }
    ft->handler = *handler;
    if (ft->handler.flags & SOX_FILE_NOSTDIO) {
      xfclose(ft->fp, ft->io_type);
      ft->fp = NULL;
    }
  }
  if (!ft->handler.startread && !ft->handler.read) {
    lsx_fail("file type `%s' isn't readable", filetype);
    goto error;
  }

  ft->mode = 'r';
  ft->filetype = lsx_strdup(filetype);
  ft->filename = lsx_strdup(path);
  if (signal)
    ft->signal = *signal;

  if (encoding)
    ft->encoding = *encoding;
  else sox_init_encodinginfo(&ft->encoding);
  set_endiannesses(ft);

  if ((ft->handler.flags & SOX_FILE_DEVICE) && !(ft->handler.flags & SOX_FILE_PHONY))
    lsx_set_signal_defaults(ft);

  ft->priv = lsx_calloc(1, ft->handler.priv_size);
  /* Read and write starters can change their formats. */
  if (ft->handler.startread && (*ft->handler.startread)(ft) != SOX_SUCCESS) {
    lsx_fail("can't open input %s `%s': %s", type, ft->filename, ft->sox_errstr);
    goto error;
  }

  /* Fill in some defaults: */
  if (sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample))
    ft->signal.precision = sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample);
  if (!(ft->handler.flags & SOX_FILE_PHONY) && !ft->signal.channels)
    ft->signal.channels = 1;

  if (sox_checkformat(ft) != SOX_SUCCESS) {
    lsx_fail("bad input format for %s `%s': %s", type, ft->filename, ft->sox_errstr);
    goto error;
  }

  if (signal) {
    if (signal->rate && signal->rate != ft->signal.rate)
      lsx_warn("can't set sample rate %g; using %g", signal->rate, ft->signal.rate);
    if (signal->channels && signal->channels != ft->signal.channels)
      lsx_warn("can't set %u channels; using %u", signal->channels, ft->signal.channels);
  }
  return ft;

error:
  if (ft->fp && ft->fp != stdin)
    xfclose(ft->fp, ft->io_type);
  free(ft->priv);
  free(ft->filename);
  free(ft->filetype);
  free(ft);
  return NULL;
}
예제 #29
0
파일: mixer.c 프로젝트: Amalerd/SoxPlayer
/*
 * Start processing
 */
static int start(sox_effect_t * effp)
{
    /*
       Hmmm, this is tricky.  Lemme think:
       channel orders are [0][0],[0][1], etc.
       i.e., 0->0, 0->1, 0->2, 0->3, 1->0, 1->1, ...
       trailing zeros are omitted
       L/R balance is x= -1 for left only, 1 for right only
       1->1 channel effects:
       changing volume by x is x,0,0,0
       1->2 channel effects:
       duplicating everywhere is 1,1,0,0
       1->4 channel effects:
       duplicating everywhere is 1,1,1,1
       2->1 channel effects:
       left only is 1,0,0,0 0,0,0,0
       right only is 0,0,0,0 1,0,0,0
       left+right is 0.5,0,0,0 0.5,0,0,0
       left-right is 1,0,0,0 -1,0,0,0
       2->2 channel effects:
       L/R balance can be done several ways.  The standard stereo
       way is both the easiest and the most sensible:
       min(1-x,1),0,0,0 0,min(1+x,1),0,0
       left to both is 1,1,0,0
       right to both is 0,0,0,0 1,1,0,0
       left+right to both is 0.5,0.5,0,0 0.5,0.5,0,0
       left-right to both is 1,1,0,0 -1,-1,0,0
       left-right to left, right-left to right is 1,-1,0,0 -1,1,0,0
       2->4 channel effects:
       front duplicated into rear is 1,0,1,0 0,1,0,1
       front swapped into rear (why?) is 1,0,0,1 0,1,1,0
       front put into rear as mono (why?) is 1,0,0.5,0.5 0,1,0.5,0.5
       4->1 channel effects:
       left front only is 1,0,0,0
       left only is 0.5,0,0,0 0,0,0,0 0.5,0,0,0
       etc.
       4->2 channel effects:
       merge front/back is 0.5,0,0,0 0,0.5,0,0 0.5,0,0,0 0,0.5,0,0
       selections similar to above
       4->4 channel effects:
       left front to all is 1,1,1,1 0,0,0,0
       right front to all is 0,0,0,0 1,1,1,1
       left f/r to all f/r is 1,1,0,0 0,0,0,0 0,0,1,1 0,0,0,0
       etc.

       The interesting cases from above (deserving of abbreviations of
       less than 16 numbers) are:

       0) n->n volume change (1 number)
       1) 1->n duplication (0 numbers)
       2) 2->1 mixdown (0 or 2 numbers)
       3) 2->2 balance (1 number)
       4) 2->2 fully general mix (4 numbers)
       5) 2->4 duplication (0 numbers)
       6) 4->1 mixdown (0 or 4 numbers)
       7) 4->2 mixdown (0, or 2 numbers)
       8) 4->4 balance (1 or 2 numbers)

       The above has one ambiguity: n->n volume change conflicts with
       n->n balance for n != 1.  In such a case, we'll prefer
       balance, since there is already a volume effect in vol.c.

       GHK 2000/11/28
     */
     priv_t * mixer = (priv_t *) effp->priv;
     double pans[16];
     int i, j;
     int ichan, ochan;

     for (i = 0;  i < 16;  i++)
         pans[i] = ((double*)&mixer->sources[0][0])[i];

     ichan = effp->in_signal.channels;
     ochan = effp->out_signal.channels;
     if (ochan == -1) {
         lsx_fail("Output must have known number of channels");
         return(SOX_EOF);
     }

     if ((ichan != 1 && ichan != 2 && ichan != 4 &&
          mixer->mix != MIX_CENTER && ochan != 1)
             ||  (ochan != 1 && ochan != 2 && ochan != 4)) {
         lsx_fail("Can't mix %d -> %d channels", ichan, ochan);
         return (SOX_EOF);
     }

     /* Handle the special-case flags */
     switch (mixer->mix) {
         case MIX_CENTER:
             if (ichan == ochan)
               return SOX_EFF_NULL;
             break;             /* Code below will handle this case */
         case 'l':
             if (ichan == 2 && ochan == 1)
             {
                 pans[0] = 1.0;
                 pans[1] = 0.0;
                 mixer->num_pans = 2;
             }
             else if (ichan == 4 && ochan == 1)
             {
                 pans[0] = 0.5;
                 pans[1] = 0.0;
                 pans[2] = 0.5;
                 pans[3] = 0.0;
                 mixer->num_pans = 4;
             }
             else
             {
                 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
                 return SOX_EOF;
             }
             break;
         case 'r':
             if (ichan == 2 && ochan == 1)
             {
                 pans[0] = 0.0;
                 pans[1] = 1.0;
                 mixer->num_pans = 2;
             }
             else if (ichan == 4 && ochan == 1)
             {
                 pans[0] = 0.0;
                 pans[1] = 0.5;
                 pans[2] = 0.0;
                 pans[3] = 0.5;
                 mixer->num_pans = 4;
             }
             else
             {
                 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
                 return SOX_EOF;
             }
             break;
         case 'f':
             if (ichan == 4 && ochan == 2)
             {
                 pans[0] = 1.0;
                 pans[1] = 0.0;
                 mixer->num_pans = 2;
             }
             else if (ichan == 4 && ochan == 1)
             {
                 pans[0] = 0.5;
                 pans[1] = 0.5;
                 pans[2] = 0.0;
                 pans[3] = 0.0;
                 mixer->num_pans = 4;
             }
             else
             {
                 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
                 return SOX_EOF;
             }
             break;
         case 'b':
             if (ichan == 4 && ochan == 2)
             {
                 pans[0] = 0.0;
                 pans[1] = 1.0;
                 mixer->num_pans = 2;
             }
             else if (ichan == 4 && ochan == 1)
             {
                 pans[0] = 0.0;
                 pans[1] = 0.0;
                 pans[2] = 0.5;
                 pans[3] = 0.5;
                 mixer->num_pans = 4;
             }
             else
             {
                 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
                 return SOX_EOF;
             }
             break;
         case '1':
             if (ichan == 2 && ochan == 1)
             {
                 pans[0] = 1.0;
                 pans[1] = 0.0;
                 mixer->num_pans = 2;
             }
             else if (ichan == 4 && ochan == 1)
             {
                 pans[0] = 1.0;
                 pans[1] = 0.0;
                 pans[2] = 0.0;
                 pans[3] = 0.0;
                 mixer->num_pans = 4;
             }
             else
             {
                 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
                 return SOX_EOF;
             }
             break;
         case '2':
             if (ichan == 2 && ochan == 1)
             {
                 pans[0] = 0.0;
                 pans[1] = 1.0;
                 mixer->num_pans = 2;
             }
             else if (ichan == 4 && ochan == 1)
             {
                 pans[0] = 0.0;
                 pans[1] = 1.0;
                 pans[2] = 0.0;
                 pans[3] = 0.0;
                 mixer->num_pans = 4;
             }
             else
             {
                 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
                 return SOX_EOF;
             }
             break;

         case '3':
             if (ichan == 4 && ochan == 1)
             {
                 pans[0] = 0.0;
                 pans[1] = 0.0;
                 pans[2] = 1.0;
                 pans[3] = 0.0;
                 mixer->num_pans = 4;
             }
             else
             {
                 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
                 return SOX_EOF;
             }
             break;

         case '4':
             if (ichan == 4 && ochan == 1)
             {
                 pans[0] = 0.0;
                 pans[1] = 0.0;
                 pans[2] = 0.0;
                 pans[3] = 1.0;
                 mixer->num_pans = 4;
             }
             else
             {
                 lsx_fail("Can't mix -%c %d -> %d channels", mixer->mix, ichan, ochan);
                 return SOX_EOF;
             }
             break;

         case MIX_SPECIFIED:
             break;
         default:
             lsx_fail("Unknown mix option");
             return SOX_EOF;
     }

     /* If number of pans is 4 or less then its a shorthand
      * representation.  If user specified it, then we have
      * garbage in our sources[][] array.  Need to clear that
      * now that all data is stored in pans[] array.
      */
     if (mixer->num_pans <= 4)
     {
         for (i = 0; i < ichan; i++)
         {
             for (j = 0; j < ochan; j++)
             {
                 mixer->sources[i][j] = 0;
             }
         }
     }

     /* If the number of pans given is 4 or fewer, handle the special */
     /* cases listed in the comments above.  The code is lengthy but */
     /* straightforward. */
     if (mixer->num_pans == 0) {
         /* CASE 1 */
         if (ichan == 1 && ochan > ichan) {
             mixer->sources[0][0] = 1.0;
             mixer->sources[0][1] = 1.0;
             mixer->sources[0][2] = 1.0;
             mixer->sources[0][3] = 1.0;
         }
         /* CASE 2, 6 */
         else if (ochan == 1) {
             mixer->sources[0][0] = 1.0 / ichan;
         }
         /* CASE 5 */
         else if (ichan == 2 && ochan == 4) {
             mixer->sources[0][0] = 1.0;
             mixer->sources[0][2] = 1.0;
             mixer->sources[1][1] = 1.0;
             mixer->sources[1][3] = 1.0;
         }
         /* CASE 7 */
         else if (ichan == 4 && ochan == 2) {
             mixer->sources[0][0] = 0.5;
             mixer->sources[1][1] = 0.5;
             mixer->sources[2][0] = 0.5;
             mixer->sources[3][1] = 0.5;
         }
         else {
             lsx_fail("You must specify at least one mix level when using mixer with an unusual number of channels.");
             return(SOX_EOF);
         }
     }
     else if (mixer->num_pans == 1) {
         /* Might be volume change or balance change */
         /* CASE 3 and CASE 8 */
         if ((ichan == 2 || ichan == 4) &&  ichan == ochan) {
             /* -1 is left only, 1 is right only */
             if (pans[0] <= 0.0) {
                 mixer->sources[1][1] = pans[0] + 1.0;
                 if (mixer->sources[1][1] < 0.0)
                     mixer->sources[1][1] = 0.0;
                 mixer->sources[0][0] = 1.0;
             }
             else {
                 mixer->sources[0][0] = 1.0 - pans[0];
                 if (mixer->sources[0][0] < 0.0)
                     mixer->sources[0][0] = 0.0;
                 mixer->sources[1][1] = 1.0;
             }
             if (ichan == 4) {
                 mixer->sources[2][2] = mixer->sources[0][0];
                 mixer->sources[3][3] = mixer->sources[1][1];
             }
         }
         else
         {
             lsx_fail("Invalid options while not mixing");
             return SOX_EOF;
         }
     }
     else if (mixer->num_pans == 2) {
         /* CASE 2 */
         if (ichan == 2 && ochan == 1) {
             mixer->sources[0][0] = pans[0];
             mixer->sources[1][0] = pans[1];
         }
         /* CASE 7 */
         else if (ichan == 4 && ochan == 2) {
             mixer->sources[0][0] = pans[0];
             mixer->sources[1][1] = pans[0];
             mixer->sources[2][0] = pans[1];
             mixer->sources[3][1] = pans[1];
         }
         /* CASE 8 */
         else if (ichan == 4 && ochan == 4) {
             /* pans[0] is front -> front, pans[1] is for back */
             mixer->sources[0][0] = pans[0];
             mixer->sources[1][1] = pans[0];
             mixer->sources[2][2] = pans[1];
             mixer->sources[3][3] = pans[1];
         }
         else
         {
             lsx_fail("Invalid options for this channel combination");
             return SOX_EOF;
         }
     }
     else if (mixer->num_pans == 3) {
       lsx_fail("Invalid options while not mixing");
       return SOX_EOF;
     }
     else if (mixer->num_pans == 4) {
         /* CASE 4 */
         if (ichan == 2 && ochan == 2) {
             /* Shorthand for 2-channel case */
             mixer->sources[0][0] = pans[0];
             mixer->sources[0][1] = pans[1];
             mixer->sources[1][0] = pans[2];
             mixer->sources[1][1] = pans[3];
         }
         /* CASE 6 */
         else if (ichan == 4 && ochan == 1) {
             mixer->sources[0][0] = pans[0];
             mixer->sources[1][0] = pans[1];
             mixer->sources[2][0] = pans[2];
             mixer->sources[3][0] = pans[3];
         }
         else
         {
             lsx_fail("Invalid options for this channel combination");
             return SOX_EOF;
         }
     }

     if (effp->in_signal.mult) {
       double max_sum = 0;

       for (j = 0; j < (int)effp->out_signal.channels; ++j) {
         double sum = 0;
         for (i = 0; i < (int)effp->in_signal.channels; ++i)
           sum += fabs(mixer->sources[mixer->mix == MIX_CENTER? 0 : i][j]);
         max_sum = max(max_sum, sum);
       }
       if (max_sum > 1)
         *effp->in_signal.mult /= max_sum;
     }

     if (effp->in_signal.channels != effp->out_signal.channels)
       return SOX_SUCCESS;

     for (i = 0; i < (int)effp->in_signal.channels; ++i)
       for (j = 0; j < (int)effp->out_signal.channels; ++j)
         if (mixer->sources[i][j] != (i == j))
           return SOX_SUCCESS;

     return SOX_EFF_NULL;
}
예제 #30
0
파일: mcompand.c 프로젝트: DeathOfMe/sox
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);
}