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); }
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; }
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(¶ms, 0, sizeof(params)); if ((ret = av_open_input_file(&ffmpeg->ctxt, ft->filename, NULL, 0, ¶ms)) < 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; }
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; }
/* * 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); }
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; }
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; }
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; }
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; }
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; }
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; }
/* * 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); }
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; }
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; }
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
/* * 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); }
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; }
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; }
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; }
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); }
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; }
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 */ }
/* 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; }
/* * 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; }
/* * 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; }
/* * 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); }
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; }
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; }
/* * 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; }
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); }