Esempio n. 1
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_drc_t* s   = (af_drc_t*)af->setup;

  switch(cmd){
  case AF_CONTROL_REINIT:
    // Sanity check
    if(!arg) return AF_ERROR;

    mp_audio_copy_config(af->data, (struct mp_audio*)arg);

    if(((struct mp_audio*)arg)->format != (AF_FORMAT_S16_NE)){
      mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
    }
    return af_test_output(af,(struct mp_audio*)arg);
  case AF_CONTROL_COMMAND_LINE:{
    int   i = 0;
    float target = DEFAULT_TARGET;
    sscanf((char*)arg,"%d:%f", &i, &target);
    if (i != 1 && i != 2)
	return AF_ERROR;
    s->method = i-1;
    s->mid_s16 = ((float)SHRT_MAX) * target;
    s->mid_float = target;
    return AF_OK;
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 2
0
static int control(struct af_instance *af, int cmd, void *arg)
{
    struct priv *priv = af->priv;

    switch (cmd) {
    case AF_CONTROL_REINIT: {
        struct mp_audio *in = arg;
        struct mp_audio orig_in = *in;
        struct mp_audio *out = af->data;

        force_in_params(af, in);
        mp_audio_copy_config(out, in);
        force_out_params(af, out);

        if (in->nch != out->nch || in->bps != out->bps) {
            MP_ERR(af, "Forced input/output formats are incompatible.\n");
            return AF_ERROR;
        }

        if (priv->fail) {
            MP_ERR(af, "Failing on purpose.\n");
            return AF_ERROR;
        }

        return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
    }
    }
    return AF_UNKNOWN;
}
Esempio n. 3
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  switch(cmd){
  case AF_CONTROL_REINIT:{
    // Sanity check
    if(!arg) return AF_ERROR;

    mp_audio_copy_config(af->data, (struct mp_audio*)arg);
    mp_audio_set_num_channels(af->data, 1);
#if 0
    if (((struct mp_audio*)arg)->format == AF_FORMAT_FLOAT)
    {
	af->data->format = AF_FORMAT_FLOAT;
	af->data->bps = 4;
	af->play = play_float;
    }// else
#endif
    {
        mp_audio_set_format(af->data, AF_FORMAT_S16);
	af->filter = play_s16;
    }

    return af_test_output(af,(struct mp_audio*)arg);
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 4
0
static int control(struct af_instance *af, int cmd, void *arg)
{
    struct priv *s = af->priv;

    switch (cmd) {
    case AF_CONTROL_REINIT: {
        struct mp_audio *in = arg;

        mp_audio_copy_config(af->data, in);
        mp_audio_force_interleaved_format(af->data);

        if (s->fast && af_fmt_from_planar(in->format) != AF_FORMAT_FLOAT) {
            mp_audio_set_format(af->data, AF_FORMAT_S16);
        } else {
            mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
        }
        if (af_fmt_is_planar(in->format))
            mp_audio_set_format(af->data, af_fmt_to_planar(af->data->format));
        return af_test_output(af, in);
    }
    case AF_CONTROL_SET_VOLUME:
        s->level = *(float *)arg;
        return AF_OK;
    case AF_CONTROL_GET_VOLUME:
        *(float *)arg = s->level;
        return AF_OK;
    }
    return AF_UNKNOWN;
}
Esempio n. 5
0
static int filter(struct af_instance *af, struct mp_audio *data)
{
    if (data)
        mp_audio_copy_config(data, af->data);
    af_add_output_frame(af, data);
    return 0;
}
Esempio n. 6
0
static int control(struct af_instance *af, int cmd, void *arg)
{
    struct priv *p = af->priv;

    switch (cmd) {
    case AF_CONTROL_REINIT: {
        struct mp_audio *in = arg;
        struct mp_audio orig_in = *in;
        struct mp_audio *out = af->data;

        in->format = AF_FORMAT_FLOATP;
        mp_audio_copy_config(out, in);

        if (p->rubber)
            rubberband_delete(p->rubber);

        int opts = p->opt_transients | p->opt_detector | p->opt_phase |
                   p->opt_window | p->opt_smoothing | p->opt_formant |
                   p->opt_pitch | p-> opt_channels |
                   RubberBandOptionProcessRealTime;

        p->rubber = rubberband_new(in->rate, in->channels.num, opts, 1.0, 1.0);
        if (!p->rubber) {
            MP_FATAL(af, "librubberband initialization failed.\n");
            return AF_ERROR;
        }

        update_speed(af, p->speed);
        update_pitch(af, p->pitch);
        control(af, AF_CONTROL_RESET, NULL);

        return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
    }
    case AF_CONTROL_SET_PLAYBACK_SPEED: {
        update_speed(af, *(double *)arg);
        return AF_OK;
    }
    case AF_CONTROL_RESET:
        if (p->rubber)
            rubberband_reset(p->rubber);
        talloc_free(p->pending);
        p->pending = NULL;
        p->rubber_delay = 0;
        return AF_OK;
    case AF_CONTROL_COMMAND: {
        char **args = arg;
        if (!strcmp(args[0], "set-pitch")) {
            char *endptr;
            double pitch = strtod(args[1], &endptr);
            if (*endptr || pitch < 0.01 || pitch > 100.0)
                return CONTROL_ERROR;
            update_pitch(af, pitch);
            return CONTROL_OK;
        } else {
            return CONTROL_ERROR;
        }
    }
    }
    return AF_UNKNOWN;
}
Esempio n. 7
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_extrastereo_t* s   = (af_extrastereo_t*)af->setup;

  switch(cmd){
  case AF_CONTROL_REINIT:{
    // Sanity check
    if(!arg) return AF_ERROR;

    mp_audio_copy_config(af->data, (struct mp_audio*)arg);
    mp_audio_set_num_channels(af->data, 2);
    if (af->data->format == AF_FORMAT_FLOAT_NE)
    {
	af->play = play_float;
    }// else
    {
        mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
	af->play = play_s16;
    }

    return af_test_output(af,(struct mp_audio*)arg);
  }
  case AF_CONTROL_COMMAND_LINE:{
    float f;
    sscanf((char*)arg,"%f", &f);
    s->mul = f;
    return AF_OK;
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 8
0
static int filter_out(struct af_instance *af)
{
    struct priv *p = af->priv;

    while (rubberband_available(p->rubber) <= 0) {
        const float *dummy[MP_NUM_CHANNELS] = {0};
        const float **in_data = dummy;
        size_t in_samples = 0;
        if (p->pending) {
            if (!p->pending->samples)
                break;

            // recover from previous EOF
            if (p->needs_reset) {
                rubberband_reset(p->rubber);
                p->rubber_delay = 0;
            }
            p->needs_reset = false;

            size_t needs = rubberband_get_samples_required(p->rubber);
            in_data = (void *)&p->pending->planes;
            in_samples = MPMIN(p->pending->samples, needs);
        }

        if (p->needs_reset)
            break; // previous EOF
        p->needs_reset = !p->pending; // EOF

        rubberband_process(p->rubber, in_data, in_samples, p->needs_reset);
        p->rubber_delay += in_samples;

        if (!p->pending)
            break;
        mp_audio_skip_samples(p->pending, in_samples);
    }

    int out_samples = rubberband_available(p->rubber);
    if (out_samples > 0) {
        struct mp_audio *out =
            mp_audio_pool_get(af->out_pool, af->data, out_samples);
        if (!out)
            return -1;
        if (p->pending)
            mp_audio_copy_config(out, p->pending);

        float **out_data = (void *)&out->planes;
        out->samples = rubberband_retrieve(p->rubber, out_data, out->samples);
        p->rubber_delay -= out->samples * p->speed;

        af_add_output_frame(af, out);
    }

    int delay_samples = p->rubber_delay;
    if (p->pending)
        delay_samples += p->pending->samples;
    af->delay = delay_samples / (af->data->rate * p->speed);

    return 0;
}
Esempio n. 9
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_surround_t *s = af->setup;
  switch(cmd){
  case AF_CONTROL_REINIT:{
    float fc;
    mp_audio_copy_config(af->data, (struct mp_audio*)arg);
    mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch*2);
    mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);

    if (af->data->nch != 4){
      mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Only stereo input is supported.\n");
      return AF_DETACH;
    }
    // Surround filer coefficients
    fc = 2.0 * 7000.0/(float)af->data->rate;
    if (-1 == af_filter_design_fir(L, s->w, &fc, LP|HAMMING, 0)){
      mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Unable to design low-pass filter.\n");
      return AF_ERROR;
    }

    // Free previous delay queues
    free(s->dl);
    free(s->dr);
    // Allocate new delay queues
    s->dl = calloc(LD,af->data->bps);
    s->dr = calloc(LD,af->data->bps);
    if((NULL == s->dl) || (NULL == s->dr))
      mp_msg(MSGT_AFILTER, MSGL_FATAL, "[delay] Out of memory\n");

    // Initialize delay queue index
    if(AF_OK != af_from_ms(1, &s->d, &s->wi, af->data->rate, 0.0, 1000.0))
      return AF_ERROR;
//    printf("%i\n",s->wi);
    s->ri = 0;

    if((af->data->format != ((struct mp_audio*)arg)->format) ||
       (af->data->bps    != ((struct mp_audio*)arg)->bps)){
      mp_audio_set_format((struct mp_audio*)arg, af->data->format);
      return AF_FALSE;
    }
    return AF_OK;
  }
  case AF_CONTROL_COMMAND_LINE:{
    float d = 0;
    sscanf((char*)arg,"%f",&d);
    if ((d < 0) || (d > 1000)){
      mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Invalid delay time, valid time values"
	     " are 0ms to 1000ms current value is %0.3f ms\n",d);
      return AF_ERROR;
    }
    s->d = d;
    return AF_OK;
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 10
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_equalizer_t* s   = (af_equalizer_t*)af->priv;

  switch(cmd){
  case AF_CONTROL_REINIT:{
    int k =0, i =0;
    float F[KM] = CF;

    s->gain_factor=0.0;

    // Sanity check
    if(!arg) return AF_ERROR;

    mp_audio_copy_config(af->data, (struct mp_audio*)arg);
    mp_audio_set_format(af->data, AF_FORMAT_FLOAT);

    // Calculate number of active filters
    s->K=KM;
    while(F[s->K-1] > (float)af->data->rate/2.2)
      s->K--;

    if(s->K != KM)
      MP_INFO(af, "Limiting the number of filters to"
             " %i due to low sample rate.\n",s->K);

    // Generate filter taps
    for(k=0;k<s->K;k++)
      bp2(s->a[k],s->b[k],F[k]/((float)af->data->rate),Q);

    // Calculate how much this plugin adds to the overall time delay
    af->delay = 2.0 / (double)af->data->rate;

    // Calculate gain factor to prevent clipping at output
    for(k=0;k<AF_NCH;k++)
    {
        for(i=0;i<KM;i++)
        {
            if(s->gain_factor < s->g[k][i]) s->gain_factor=s->g[k][i];
        }
    }

    s->gain_factor=log10(s->gain_factor + 1.0) * 20.0;

    if(s->gain_factor > 0.0)
    {
        s->gain_factor=0.1+(s->gain_factor/12.0);
    }else{
        s->gain_factor=1;
    }

    return af_test_output(af,arg);
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 11
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
	switch(cmd){
		case AF_CONTROL_REINIT:
                mp_audio_copy_config(af->data, (struct mp_audio*)arg);
                mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
		return af_test_output(af,(struct mp_audio*)arg);
	}
	return AF_UNKNOWN;
}
Esempio n. 12
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_delay_t* s = af->setup;
  switch(cmd){
  case AF_CONTROL_REINIT:{
    int i;

    // Free prevous delay queues
    for(i=0;i<af->data->nch;i++)
      free(s->q[i]);

    mp_audio_copy_config(af->data, (struct mp_audio*)arg);
    mp_audio_force_interleaved_format(af->data);

    // Allocate new delay queues
    for(i=0;i<af->data->nch;i++){
      s->q[i] = calloc(L,af->data->bps);
      if(NULL == s->q[i])
	mp_msg(MSGT_AFILTER, MSGL_FATAL, "[delay] Out of memory\n");
    }

    if(AF_OK != af_from_ms(AF_NCH, s->d, s->wi, af->data->rate, 0.0, 1000.0))
      return AF_ERROR;
    s->ri = 0;
    for(i=0;i<AF_NCH;i++){
      mp_msg(MSGT_AFILTER, MSGL_DBG2, "[delay] Channel %i delayed by %0.3fms\n",
             i,MPCLAMP(s->d[i],0.0,1000.0));
      mp_msg(MSGT_AFILTER, MSGL_DBG3, "[delay] Channel %i delayed by %i samples\n",
             i,s->wi[i]);
    }
    return AF_OK;
  }
  case AF_CONTROL_COMMAND_LINE:{
    int n = 1;
    int i = 0;
    char* cl = arg;
    while(n && i < AF_NCH ){
      sscanf(cl,"%f:%n",&s->d[i],&n);
      if(n==0 || cl[n-1] == '\0')
	break;
      cl=&cl[n];
      i++;
    }
    return AF_OK;
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 13
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  switch(cmd){
  case AF_CONTROL_REINIT:
    // Sanity check
    if(!arg) return AF_ERROR;

    mp_audio_force_interleaved_format((struct mp_audio*)arg);
    mp_audio_copy_config(af->data, (struct mp_audio*)arg);

    if(((struct mp_audio*)arg)->format != (AF_FORMAT_S16)){
      mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
    }
    return af_test_output(af,(struct mp_audio*)arg);
  }
  return AF_UNKNOWN;
}
Esempio n. 14
0
static int filter_out(struct af_instance *af)
{
    struct priv *p = af->priv;

    if (!p->graph)
        goto error;

    AVFrame *frame = av_frame_alloc();
    if (!frame)
        goto error;

    int err = av_buffersink_get_frame(p->out, frame);
    if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) {
        // Not an error situation - no more output buffers in queue.
        // AVERROR_EOF means we shouldn't even give the filter more
        // input, but we don't handle that completely correctly.
        av_frame_free(&frame);
        p->eof |= err == AVERROR_EOF;
        return 0;
    }

    struct mp_audio *out = mp_audio_from_avframe(frame);
    if (!out)
        goto error;

    mp_audio_copy_config(out, af->data);

    if (frame->pts != AV_NOPTS_VALUE) {
        double in_time = p->samples_in / (double)af->fmt_in.rate;
        double out_time = frame->pts * av_q2d(p->timebase_out);
        // Need pts past the last output sample.
        out_time += out->samples / (double)out->rate;

        af->delay = in_time - out_time;
    }

    get_metadata_from_av_frame(af, frame);
    af_add_output_frame(af, out);
    av_frame_free(&frame);
    return 0;
error:
    av_frame_free(&frame);
    return -1;
}
Esempio n. 15
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_surround_t *s = af->priv;
  switch(cmd){
  case AF_CONTROL_REINIT:{
    struct mp_audio *in = arg;
    float fc;
    if (!mp_chmap_is_stereo(&in->channels)) {
        MP_ERR(af, "Only stereo input is supported.\n");
        return AF_DETACH;
    }

    mp_audio_set_format(in, AF_FORMAT_FLOAT);
    mp_audio_copy_config(af->data, in);
    mp_audio_set_channels_old(af->data, in->nch * 2);

    // Surround filer coefficients
    fc = 2.0 * 7000.0/(float)af->data->rate;
    if (-1 == af_filter_design_fir(L, s->w, &fc, LP|HAMMING, 0)){
      MP_ERR(af, "Unable to design low-pass filter.\n");
      return AF_ERROR;
    }

    // Free previous delay queues
    free(s->dl);
    free(s->dr);
    // Allocate new delay queues
    s->dl = calloc(LD,af->data->bps);
    s->dr = calloc(LD,af->data->bps);
    if((NULL == s->dl) || (NULL == s->dr))
      MP_FATAL(af, "Out of memory\n");

    // Initialize delay queue index
    if(AF_OK != af_from_ms(1, &s->d, &s->wi, af->data->rate, 0.0, 1000.0))
      return AF_ERROR;
//    printf("%i\n",s->wi);
    s->ri = 0;

    return AF_OK;
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 16
0
File: af_delay.c Progetto: agiz/mpv
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_delay_t* s = af->priv;
  switch(cmd){
  case AF_CONTROL_REINIT:{
    int i;
    struct mp_audio *in = arg;

    if (in->bps != 1 && in->bps != 2 && in->bps != 4) {
      mp_msg(MSGT_AFILTER, MSGL_FATAL, "[delay] Sample format not supported\n");
      return AF_ERROR;
    }

    // Free prevous delay queues
    for(i=0;i<af->data->nch;i++)
      free(s->q[i]);

    mp_audio_force_interleaved_format(in);
    mp_audio_copy_config(af->data, in);

    // Allocate new delay queues
    for(i=0;i<af->data->nch;i++){
      s->q[i] = calloc(L,af->data->bps);
      if(NULL == s->q[i])
	mp_msg(MSGT_AFILTER, MSGL_FATAL, "[delay] Out of memory\n");
    }

    if(AF_OK != af_from_ms(AF_NCH, s->d, s->wi, af->data->rate, 0.0, 1000.0))
      return AF_ERROR;
    s->ri = 0;
    for(i=0;i<AF_NCH;i++){
      mp_msg(MSGT_AFILTER, MSGL_DBG2, "[delay] Channel %i delayed by %0.3fms\n",
             i,MPCLAMP(s->d[i],0.0,1000.0));
      mp_msg(MSGT_AFILTER, MSGL_DBG3, "[delay] Channel %i delayed by %i samples\n",
             i,s->wi[i]);
    }
    return AF_OK;
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 17
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_sinesuppress_t* s   = (af_sinesuppress_t*)af->setup;

  switch(cmd){
  case AF_CONTROL_REINIT:{
    // Sanity check
    if(!arg) return AF_ERROR;

    mp_audio_copy_config(af->data, (struct mp_audio*)arg);
    mp_audio_set_num_channels(af->data, 1);
#if 0
    if (((struct mp_audio*)arg)->format == AF_FORMAT_FLOAT_NE)
    {
	af->data->format = AF_FORMAT_FLOAT_NE;
	af->data->bps = 4;
	af->play = play_float;
    }// else
#endif
    {
        mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
	af->play = play_s16;
    }

    return af_test_output(af,(struct mp_audio*)arg);
  }
  case AF_CONTROL_COMMAND_LINE:{
    float f1,f2;
    sscanf((char*)arg,"%f:%f", &f1,&f2);
    s->freq = f1;
    s->decay = f2;
    return AF_OK;
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 18
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_scaletempo_t* s = af->setup;
  switch(cmd){
  case AF_CONTROL_REINIT:{
    struct mp_audio* data = (struct mp_audio*)arg;
    float srate = data->rate / 1000;
    int nch = data->nch;
    int bps;
    int use_int = 0;
    int frames_stride, frames_overlap;
    int i, j;

    mp_msg(MSGT_AFILTER, MSGL_V,
           "[scaletempo] %.3f speed * %.3f scale_nominal = %.3f\n",
           s->speed, s->scale_nominal, s->scale);

    mp_audio_copy_config(af->data, data);

    if (s->scale == 1.0) {
      if (s->speed_tempo && s->speed_pitch)
        return AF_DETACH;
      af->delay = 0;
      af->mul = 1;
      return af_test_output(af, data);
    }

    if (data->format == AF_FORMAT_S16_NE) {
      use_int = 1;
    } else {
      mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
    }
    bps = af->data->bps;

    frames_stride           = srate * s->ms_stride;
    s->bytes_stride         = frames_stride * bps * nch;
    s->bytes_stride_scaled  = s->scale * s->bytes_stride;
    s->frames_stride_scaled = s->scale * frames_stride;
    s->frames_stride_error  = 0;
    af->mul = (double)s->bytes_stride / s->bytes_stride_scaled;
    af->delay = 0;

    frames_overlap = frames_stride * s->percent_overlap;
    if (frames_overlap <= 0) {
      s->bytes_standing   = s->bytes_stride;
      s->samples_standing = s->bytes_standing / bps;
      s->output_overlap   = NULL;
      s->bytes_overlap    = 0;
    } else {
      s->samples_overlap  = frames_overlap * nch;
      s->bytes_overlap    = frames_overlap * nch * bps;
      s->bytes_standing   = s->bytes_stride - s->bytes_overlap;
      s->samples_standing = s->bytes_standing / bps;
      s->buf_overlap      = realloc(s->buf_overlap, s->bytes_overlap);
      s->table_blend      = realloc(s->table_blend, s->bytes_overlap * 4);
      if(!s->buf_overlap || !s->table_blend) {
        mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n");
        return AF_ERROR;
      }
      memset(s->buf_overlap, 0, s->bytes_overlap);
      if (use_int) {
        int32_t* pb = s->table_blend;
        int64_t blend = 0;
        for (i=0; i<frames_overlap; i++) {
          int32_t v = blend / frames_overlap;
          for (j=0; j<nch; j++) {
            *pb++ = v;
          }
          blend += 65536;  // 2^16
        }
        s->output_overlap = output_overlap_s16;
      } else {
        float* pb = s->table_blend;
        for (i=0; i<frames_overlap; i++) {
          float v = i / (float)frames_overlap;
          for (j=0; j<nch; j++) {
            *pb++ = v;
          }
        }
        s->output_overlap = output_overlap_float;
      }
    }

    s->frames_search = (frames_overlap > 1) ? srate * s->ms_search : 0;
    if (s->frames_search <= 0) {
      s->best_overlap_offset = NULL;
    } else {
      if (use_int) {
        int64_t t = frames_overlap;
        int32_t n = 8589934588LL / (t * t);  // 4 * (2^31 - 1) / t^2
        int32_t* pw;
        s->buf_pre_corr = realloc(s->buf_pre_corr, s->bytes_overlap * 2 + UNROLL_PADDING);
        s->table_window = realloc(s->table_window, s->bytes_overlap * 2 - nch * bps * 2);
        if(!s->buf_pre_corr || !s->table_window) {
          mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n");
          return AF_ERROR;
        }
        memset((char *)s->buf_pre_corr + s->bytes_overlap * 2, 0, UNROLL_PADDING);
        pw = s->table_window;
        for (i=1; i<frames_overlap; i++) {
          int32_t v = ( i * (t - i) * n ) >> 15;
          for (j=0; j<nch; j++) {
            *pw++ = v;
          }
        }
        s->best_overlap_offset = best_overlap_offset_s16;
      } else {
        float* pw;
        s->buf_pre_corr = realloc(s->buf_pre_corr, s->bytes_overlap);
        s->table_window = realloc(s->table_window, s->bytes_overlap - nch * bps);
        if(!s->buf_pre_corr || !s->table_window) {
          mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n");
          return AF_ERROR;
        }
        pw = s->table_window;
        for (i=1; i<frames_overlap; i++) {
          float v = i * (frames_overlap - i);
          for (j=0; j<nch; j++) {
            *pw++ = v;
          }
        }
        s->best_overlap_offset = best_overlap_offset_float;
      }
    }

    s->bytes_per_frame = bps * nch;
    s->num_channels    = nch;

    s->bytes_queue
      = (s->frames_search + frames_stride + frames_overlap) * bps * nch;
    s->buf_queue = realloc(s->buf_queue, s->bytes_queue + UNROLL_PADDING);
    if(!s->buf_queue) {
      mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n");
      return AF_ERROR;
    }

    s->bytes_queued = 0;
    s->bytes_to_slide = 0;

    mp_msg (MSGT_AFILTER, MSGL_DBG2, "[scaletempo] "
            "%.2f stride_in, %i stride_out, %i standing, "
            "%i overlap, %i search, %i queue, %s mode\n",
            s->frames_stride_scaled,
            (int)(s->bytes_stride / nch / bps),
            (int)(s->bytes_standing / nch / bps),
            (int)(s->bytes_overlap / nch / bps),
            s->frames_search,
            (int)(s->bytes_queue / nch / bps),
            (use_int?"s16":"float"));

    return af_test_output(af, (struct mp_audio*)arg);
  }
  case AF_CONTROL_PLAYBACK_SPEED | AF_CONTROL_SET:{
    if (s->speed_tempo) {
      if (s->speed_pitch) {
        break;
      }
      s->speed = *(float*)arg;
      s->scale = s->speed * s->scale_nominal;
    } else {
      if (s->speed_pitch) {
        s->speed = 1 / *(float*)arg;
        s->scale = s->speed * s->scale_nominal;
        break;
      }
    }
    return AF_OK;
  }
  case AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_SET:{
    s->scale = *(float*)arg;
    s->scale = s->speed * s->scale_nominal;
    return AF_OK;
  }
  case AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_GET:
    *(float*)arg = s->scale;
    return AF_OK;
  case AF_CONTROL_COMMAND_LINE:{
    strarg_t speed = {};
    opt_t subopts[] = {
      {"scale",   OPT_ARG_FLOAT, &s->scale_nominal, NULL},
      {"stride",  OPT_ARG_FLOAT, &s->ms_stride, NULL},
      {"overlap", OPT_ARG_FLOAT, &s->percent_overlap, NULL},
      {"search",  OPT_ARG_FLOAT, &s->ms_search, NULL},
      {"speed",   OPT_ARG_STR,   &speed, NULL},
      {NULL},
    };
    if (subopt_parse(arg, subopts) != 0) {
      return AF_ERROR;
    }
    if (s->scale_nominal <= 0) {
        mp_msg(MSGT_AFILTER, MSGL_ERR, "[scaletempo] %s: %s: scale > 0\n",
               mp_gtext("error parsing command line"),
               mp_gtext("value out of range"));
      return AF_ERROR;
    }
    if (s->ms_stride <= 0) {
        mp_msg(MSGT_AFILTER, MSGL_ERR, "[scaletempo] %s: %s: stride > 0\n",
               mp_gtext("error parsing command line"),
               mp_gtext("value out of range"));
      return AF_ERROR;
    }
    if (s->percent_overlap < 0 || s->percent_overlap > 1) {
        mp_msg(MSGT_AFILTER, MSGL_ERR,
               "[scaletempo] %s: %s: 0 <= overlap <= 1\n",
               mp_gtext("error parsing command line"),
               mp_gtext("value out of range"));
      return AF_ERROR;
    }
    if (s->ms_search < 0) {
        mp_msg(MSGT_AFILTER, MSGL_ERR, "[scaletempo] %s: %s: search >= 0\n",
               mp_gtext("error parsing command line"),
               mp_gtext("value out of range"));
      return AF_ERROR;
    }
    if (speed.len > 0) {
      if (strcmp(speed.str, "pitch") == 0) {
        s->speed_tempo = 0;
        s->speed_pitch = 1;
      } else if (strcmp(speed.str, "tempo") == 0) {
        s->speed_tempo = 1;
        s->speed_pitch = 0;
      } else if (strcmp(speed.str, "none") == 0) {
        s->speed_tempo = 0;
        s->speed_pitch = 0;
      } else if (strcmp(speed.str, "both") == 0) {
        s->speed_tempo = 1;
        s->speed_pitch = 1;
      } else {
        mp_msg(MSGT_AFILTER, MSGL_ERR,
               "[scaletempo] %s: %s: speed=[pitch|tempo|none|both]\n",
               mp_gtext("error parsing command line"),
               mp_gtext("value out of range"));
        return AF_ERROR;
      }
    }
    s->scale = s->speed * s->scale_nominal;
    mp_msg(MSGT_AFILTER, MSGL_DBG2, "[scaletempo] %6.3f scale, %6.2f stride, %6.2f overlap, %6.2f search, speed = %s\n", s->scale_nominal, s->ms_stride, s->percent_overlap, s->ms_search, (s->speed_tempo?(s->speed_pitch?"tempo and speed":"tempo"):(s->speed_pitch?"pitch":"none")));
    return AF_OK;
  }
  }
Esempio n. 19
0
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_equalizer_t* s   = (af_equalizer_t*)af->setup;

  switch(cmd){
  case AF_CONTROL_REINIT:{
    int k =0, i =0;
    float F[KM] = CF;

    s->gain_factor=0.0;

    // Sanity check
    if(!arg) return AF_ERROR;

    mp_audio_copy_config(af->data, (struct mp_audio*)arg);
    mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);

    // Calculate number of active filters
    s->K=KM;
    while(F[s->K-1] > (float)af->data->rate/2.2)
      s->K--;

    if(s->K != KM)
      mp_msg(MSGT_AFILTER, MSGL_INFO, "[equalizer] Limiting the number of filters to"
	     " %i due to low sample rate.\n",s->K);

    // Generate filter taps
    for(k=0;k<s->K;k++)
      bp2(s->a[k],s->b[k],F[k]/((float)af->data->rate),Q);

    // Calculate how much this plugin adds to the overall time delay
    af->delay = 2 * af->data->nch * af->data->bps;

    // Calculate gain factor to prevent clipping at output
    for(k=0;k<AF_NCH;k++)
    {
        for(i=0;i<KM;i++)
        {
            if(s->gain_factor < s->g[k][i]) s->gain_factor=s->g[k][i];
        }
    }

    s->gain_factor=log10(s->gain_factor + 1.0) * 20.0;

    if(s->gain_factor > 0.0)
    {
        s->gain_factor=0.1+(s->gain_factor/12.0);
    }else{
        s->gain_factor=1;
    }

    return af_test_output(af,arg);
  }
  case AF_CONTROL_COMMAND_LINE:{
    float g[10]={0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
    int i,j;
    sscanf((char*)arg,"%f:%f:%f:%f:%f:%f:%f:%f:%f:%f", &g[0], &g[1],
	   &g[2], &g[3], &g[4], &g[5], &g[6], &g[7], &g[8] ,&g[9]);
    for(i=0;i<AF_NCH;i++){
      for(j=0;j<KM;j++){
	((af_equalizer_t*)af->setup)->g[i][j] =
	  pow(10.0,clamp(g[j],G_MIN,G_MAX)/20.0)-1.0;
      }
    }
    return AF_OK;
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 20
0
// Initialization and runtime control
static int control(struct af_instance *af, int cmd, void *arg)
{
    af_scaletempo_t *s = af->priv;
    switch (cmd) {
    case AF_CONTROL_REINIT: {
        struct mp_audio *data = (struct mp_audio *)arg;
        float srate = data->rate / 1000;
        int nch = data->nch;
        int use_int = 0;

        mp_msg(MSGT_AFILTER, MSGL_V,
               "[scaletempo] %.3f speed * %.3f scale_nominal = %.3f\n",
               s->speed, s->scale_nominal, s->scale);

        mp_audio_force_interleaved_format(data);
        mp_audio_copy_config(af->data, data);

        if (s->scale == 1.0) {
            if (s->speed_tempo && s->speed_pitch)
                return AF_DETACH;
            af->delay = 0;
            af->mul = 1;
            return af_test_output(af, data);
        }

        if (data->format == AF_FORMAT_S16) {
            use_int = 1;
        } else {
            mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
        }
        int bps = af->data->bps;

        s->frames_stride        = srate * s->ms_stride;
        s->bytes_stride         = s->frames_stride * bps * nch;
        s->frames_stride_scaled = s->scale * s->frames_stride;
        s->frames_stride_error  = 0;
        af->mul = 1.0 / s->scale;
        af->delay = 0;

        int frames_overlap = s->frames_stride * s->percent_overlap;
        if (frames_overlap <= 0) {
            s->bytes_standing   = s->bytes_stride;
            s->samples_standing = s->bytes_standing / bps;
            s->output_overlap   = NULL;
            s->bytes_overlap    = 0;
        } else {
            s->samples_overlap  = frames_overlap * nch;
            s->bytes_overlap    = frames_overlap * nch * bps;
            s->bytes_standing   = s->bytes_stride - s->bytes_overlap;
            s->samples_standing = s->bytes_standing / bps;
            s->buf_overlap      = realloc(s->buf_overlap, s->bytes_overlap);
            s->table_blend      = realloc(s->table_blend, s->bytes_overlap * 4);
            if (!s->buf_overlap || !s->table_blend) {
                mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n");
                return AF_ERROR;
            }
            memset(s->buf_overlap, 0, s->bytes_overlap);
            if (use_int) {
                int32_t *pb = s->table_blend;
                int64_t blend = 0;
                for (int i = 0; i < frames_overlap; i++) {
                    int32_t v = blend / frames_overlap;
                    for (int j = 0; j < nch; j++)
                        *pb++ = v;
                    blend += 65536; // 2^16
                }
                s->output_overlap = output_overlap_s16;
            } else {
                float *pb = s->table_blend;
                for (int i = 0; i < frames_overlap; i++) {
                    float v = i / (float)frames_overlap;
                    for (int j = 0; j < nch; j++)
                        *pb++ = v;
                }
                s->output_overlap = output_overlap_float;
            }
        }

        s->frames_search = (frames_overlap > 1) ? srate * s->ms_search : 0;
        if (s->frames_search <= 0)
            s->best_overlap_offset = NULL;
        else {
            if (use_int) {
                int64_t t = frames_overlap;
                int32_t n = 8589934588LL / (t * t); // 4 * (2^31 - 1) / t^2
                s->buf_pre_corr = realloc(s->buf_pre_corr,
                                          s->bytes_overlap * 2 + UNROLL_PADDING);
                s->table_window = realloc(s->table_window,
                                          s->bytes_overlap * 2 - nch * bps * 2);
                if (!s->buf_pre_corr || !s->table_window) {
                    mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n");
                    return AF_ERROR;
                }
                memset((char *)s->buf_pre_corr + s->bytes_overlap * 2, 0,
                       UNROLL_PADDING);
                int32_t *pw = s->table_window;
                for (int i = 1; i < frames_overlap; i++) {
                    int32_t v = (i * (t - i) * n) >> 15;
                    for (int j = 0; j < nch; j++)
                        *pw++ = v;
                }
                s->best_overlap_offset = best_overlap_offset_s16;
            } else {
                s->buf_pre_corr = realloc(s->buf_pre_corr, s->bytes_overlap);
                s->table_window = realloc(s->table_window,
                                          s->bytes_overlap - nch * bps);
                if (!s->buf_pre_corr || !s->table_window) {
                    mp_msg(MSGT_AFILTER, MSGL_FATAL,
                           "[scaletempo] Out of memory\n");
                    return AF_ERROR;
                }
                float *pw = s->table_window;
                for (int i = 1; i < frames_overlap; i++) {
                    float v = i * (frames_overlap - i);
                    for (int j = 0; j < nch; j++)
                        *pw++ = v;
                }
                s->best_overlap_offset = best_overlap_offset_float;
            }
        }

        s->bytes_per_frame = bps * nch;
        s->num_channels    = nch;

        s->bytes_queue = (s->frames_search + s->frames_stride + frames_overlap)
                         * bps * nch;
        s->buf_queue = realloc(s->buf_queue, s->bytes_queue + UNROLL_PADDING);
        if (!s->buf_queue) {
            mp_msg(MSGT_AFILTER, MSGL_FATAL, "[scaletempo] Out of memory\n");
            return AF_ERROR;
        }

        s->bytes_queued = 0;
        s->bytes_to_slide = 0;

        mp_msg(MSGT_AFILTER, MSGL_DBG2, "[scaletempo] "
               "%.2f stride_in, %i stride_out, %i standing, "
               "%i overlap, %i search, %i queue, %s mode\n",
               s->frames_stride_scaled,
               (int)(s->bytes_stride / nch / bps),
               (int)(s->bytes_standing / nch / bps),
               (int)(s->bytes_overlap / nch / bps),
               s->frames_search,
               (int)(s->bytes_queue / nch / bps),
               (use_int ? "s16" : "float"));

        return af_test_output(af, (struct mp_audio *)arg);
    }
    case AF_CONTROL_SET_PLAYBACK_SPEED: {
        if (s->speed_tempo) {
            if (s->speed_pitch)
                break;
            s->speed = *(double *)arg;
            s->scale = s->speed * s->scale_nominal;
        } else {
            if (s->speed_pitch) {
                s->speed = 1 / *(double *)arg;
                s->scale = s->speed * s->scale_nominal;
                break;
            }
        }
        return AF_OK;
    }
    case AF_CONTROL_RESET:
        s->bytes_queued = 0;
        s->bytes_to_slide = 0;
        s->frames_stride_error = 0;
        memset(s->buf_overlap, 0, s->bytes_overlap);
    }
Esempio n. 21
0
// Initialization and runtime control
static int control(struct af_instance *af, int cmd, void *arg)
{
    af_ac3enc_t *s  = af->priv;
    static const int default_bit_rate[AC3_MAX_CHANNELS+1] = \
        {0, 96000, 192000, 256000, 384000, 448000, 448000};

    switch (cmd){
    case AF_CONTROL_REINIT: {
        struct mp_audio *in = arg;
        struct mp_audio orig_in = *in;

        if (AF_FORMAT_IS_SPECIAL(in->format) || in->nch < s->cfg_min_channel_num)
            return AF_DETACH;

        mp_audio_set_format(in, s->in_sampleformat);

        if (in->rate != 48000 && in->rate != 44100 && in->rate != 32000)
            in->rate = 48000;
        af->data->rate = in->rate;

        mp_chmap_reorder_to_lavc(&in->channels);
        if (in->nch > AC3_MAX_CHANNELS)
            mp_audio_set_num_channels(in, AC3_MAX_CHANNELS);

        mp_audio_set_format(af->data, AF_FORMAT_S_AC3);
        mp_audio_set_num_channels(af->data, 2);

        if (!mp_audio_config_equals(in, &orig_in))
            return AF_FALSE;

        s->in_samples = AC3_FRAME_SIZE;
        if (s->cfg_add_iec61937_header) {
            s->out_samples = AC3_FRAME_SIZE;
        } else {
            s->out_samples = AC3_MAX_CODED_FRAME_SIZE / af->data->sstride;
        }

        mp_audio_copy_config(s->input, in);
        mp_audio_realloc(s->input, s->in_samples);
        s->input->samples = 0;

        talloc_free(s->pending);
        s->pending = NULL;

        MP_DBG(af, "af_lavcac3enc reinit: %d, %d, %d.\n",
               in->nch, in->rate, s->in_samples);

        int bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[in->nch];

        if (s->lavc_actx->channels != in->nch ||
            s->lavc_actx->sample_rate != in->rate ||
            s->lavc_actx->bit_rate != bit_rate)
        {
            avcodec_close(s->lavc_actx);

            // Put sample parameters
            s->lavc_actx->channels = in->nch;
            s->lavc_actx->channel_layout = mp_chmap_to_lavc(&in->channels);
            s->lavc_actx->sample_rate = in->rate;
            s->lavc_actx->bit_rate = bit_rate;

            if (avcodec_open2(s->lavc_actx, s->lavc_acodec, NULL) < 0) {
                MP_ERR(af, "Couldn't open codec %s, br=%d.\n", "ac3", bit_rate);
                return AF_ERROR;
            }
        }
        if (s->lavc_actx->frame_size != AC3_FRAME_SIZE) {
            MP_ERR(af, "lavcac3enc: unexpected ac3 "
                   "encoder frame size %d\n", s->lavc_actx->frame_size);
            return AF_ERROR;
        }
        return AF_OK;
    }
    }
    return AF_UNKNOWN;
}
Esempio n. 22
0
/* Initialization and runtime control
   af audio filter instance
   cmd control command
   arg argument
*/
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_export_t* s = af->priv;
  switch (cmd){
  case AF_CONTROL_REINIT:{
    int i=0;
    int mapsize;

    // Free previous buffers
    free(s->buf[0]);

    // unmap previous area
    if(s->mmap_area)
      munmap(s->mmap_area, SIZE_HEADER + (af->data->bps*s->sz*af->data->nch));
    // close previous file descriptor
    if(s->fd)
      close(s->fd);

    // Accept only int16_t as input format (which sucks)
    mp_audio_copy_config(af->data, (struct mp_audio*)arg);
    mp_audio_set_format(af->data, AF_FORMAT_S16);

    // Allocate new buffers (as one continuous block)
    s->buf[0] = calloc(s->sz*af->data->nch, af->data->bps);
    if(NULL == s->buf[0]) {
      MP_FATAL(af, "Out of memory\n");
      return AF_ERROR;
    }
    for(i = 1; i < af->data->nch; i++)
      s->buf[i] = (uint8_t *)s->buf[0] + i*s->sz*af->data->bps;

    if (!s->filename) {
        MP_FATAL(af, "No filename set.\n");
        return AF_ERROR;
    }

    // Init memory mapping
    s->fd = open(s->filename, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
    MP_INFO(af, "Exporting to file: %s\n", s->filename);
    if(s->fd < 0) {
      MP_FATAL(af, "Could not open/create file: %s\n",
             s->filename);
      return AF_ERROR;
    }

    // header + buffer
    mapsize = (SIZE_HEADER + (af->data->bps * s->sz * af->data->nch));

    // grow file to needed size
    for(i = 0; i < mapsize; i++){
      char null = 0;
      write(s->fd, (void*) &null, 1);
    }

    // mmap size
    s->mmap_area = mmap(0, mapsize, PROT_READ|PROT_WRITE,MAP_SHARED, s->fd, 0);
    if(s->mmap_area == NULL)
      MP_FATAL(af, "Could not mmap file %s\n", s->filename);
    MP_INFO(af, "Memory mapped to file: %s (%p)\n",
           s->filename, s->mmap_area);

    // Initialize header
    *((int*)s->mmap_area) = af->data->nch;
    *((int*)s->mmap_area + 1) = s->sz * af->data->bps * af->data->nch;
    msync(s->mmap_area, mapsize, MS_ASYNC);

    // Use test_output to return FALSE if necessary
    return af_test_output(af, (struct mp_audio*)arg);
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 23
0
/* Initialization and runtime control
   af audio filter instance
   cmd control command
   arg argument
*/
static int control(struct af_instance* af, int cmd, void* arg)
{
  af_export_t* s = af->setup;
  switch (cmd){
  case AF_CONTROL_REINIT:{
    int i=0;
    int mapsize;

    // Free previous buffers
    if (s->buf)
      free(s->buf[0]);

    // unmap previous area
    if(s->mmap_area)
      munmap(s->mmap_area, SIZE_HEADER + (af->data->bps*s->sz*af->data->nch));
    // close previous file descriptor
    if(s->fd)
      close(s->fd);

    // Accept only int16_t as input format (which sucks)
    mp_audio_copy_config(af->data, (struct mp_audio*)arg);
    mp_audio_set_format(af->data, AF_FORMAT_S16);

    // If buffer length isn't set, set it to the default value
    if(s->sz == 0)
      s->sz = DEF_SZ;

    // Allocate new buffers (as one continuous block)
    s->buf[0] = calloc(s->sz*af->data->nch, af->data->bps);
    if(NULL == s->buf[0])
      mp_msg(MSGT_AFILTER, MSGL_FATAL, "[export] Out of memory\n");
    for(i = 1; i < af->data->nch; i++)
      s->buf[i] = (uint8_t *)s->buf[0] + i*s->sz*af->data->bps;

    if (!s->filename) {
        mp_msg(MSGT_AFILTER, MSGL_FATAL, "[export] No filename set.\n");
        return AF_ERROR;
    }

    // Init memory mapping
    s->fd = open(s->filename, O_RDWR | O_CREAT | O_TRUNC, 0640);
    mp_msg(MSGT_AFILTER, MSGL_INFO, "[export] Exporting to file: %s\n", s->filename);
    if(s->fd < 0) {
      mp_msg(MSGT_AFILTER, MSGL_FATAL, "[export] Could not open/create file: %s\n",
	     s->filename);
      return AF_ERROR;
    }

    // header + buffer
    mapsize = (SIZE_HEADER + (af->data->bps * s->sz * af->data->nch));

    // grow file to needed size
    for(i = 0; i < mapsize; i++){
      char null = 0;
      write(s->fd, (void*) &null, 1);
    }

    // mmap size
    s->mmap_area = mmap(0, mapsize, PROT_READ|PROT_WRITE,MAP_SHARED, s->fd, 0);
    if(s->mmap_area == NULL)
      mp_msg(MSGT_AFILTER, MSGL_FATAL, "[export] Could not mmap file %s\n", s->filename);
    mp_msg(MSGT_AFILTER, MSGL_INFO, "[export] Memory mapped to file: %s (%p)\n",
	   s->filename, s->mmap_area);

    // Initialize header
    *((int*)s->mmap_area) = af->data->nch;
    *((int*)s->mmap_area + 1) = s->sz * af->data->bps * af->data->nch;
    msync(s->mmap_area, mapsize, MS_ASYNC);

    // Use test_output to return FALSE if necessary
    return af_test_output(af, (struct mp_audio*)arg);
  }
  case AF_CONTROL_COMMAND_LINE:{
    int i=0;
    char *str = arg;

    if (!str){
      talloc_free(s->filename);

      s->filename = mp_find_user_config_file(SHARED_FILE);
      return AF_OK;
    }

    while((str[i]) && (str[i] != ':'))
      i++;

    talloc_free(s->filename);

    s->filename = talloc_array_size(NULL, 1, i + 1);
    memcpy(s->filename, str, i);
    s->filename[i] = 0;

    sscanf(str + i + 1, "%d", &(s->sz));

    if((s->sz <= 0) || (s->sz > 2048))
      mp_msg(MSGT_AFILTER, MSGL_ERR, "[export] Buffer size must be between"
	      " 1 and 2048\n" );

    return AF_OK;

  }
  }
  return AF_UNKNOWN;
}
Esempio n. 24
0
// Initialization and runtime control
static int control(struct af_instance *af, int cmd, void *arg)
{
    af_ac3enc_t *s  = af->priv;
    static const int default_bit_rate[AC3_MAX_CHANNELS+1] = \
        {0, 96000, 192000, 256000, 384000, 448000, 448000};

    switch (cmd){
    case AF_CONTROL_REINIT: {
        struct mp_audio *in = arg;
        struct mp_audio orig_in = *in;

        if (!af_fmt_is_pcm(in->format) || in->nch < s->cfg_min_channel_num)
            return AF_DETACH;

        // At least currently, the AC3 encoder doesn't export sample rates.
        in->rate = 48000;
        select_encode_format(s->lavc_actx, in);

        af->data->rate = in->rate;
        mp_audio_set_format(af->data, AF_FORMAT_S_AC3);
        mp_audio_set_num_channels(af->data, 2);

        if (!mp_audio_config_equals(in, &orig_in))
            return AF_FALSE;

        if (s->cfg_add_iec61937_header) {
            s->out_samples = AC3_FRAME_SIZE;
        } else {
            s->out_samples = AC3_MAX_CODED_FRAME_SIZE / af->data->sstride;
        }

        mp_audio_copy_config(s->input, in);

        talloc_free(s->pending);
        s->pending = NULL;

        MP_DBG(af, "reinit: %d, %d, %d.\n", in->nch, in->rate, s->in_samples);

        int bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[in->nch];

        if (s->lavc_actx->channels != in->nch ||
            s->lavc_actx->sample_rate != in->rate ||
            s->lavc_actx->bit_rate != bit_rate)
        {
            avcodec_close(s->lavc_actx);

            // Put sample parameters
            s->lavc_actx->sample_fmt = af_to_avformat(in->format);
            s->lavc_actx->channels = in->nch;
            s->lavc_actx->channel_layout = mp_chmap_to_lavc(&in->channels);
            s->lavc_actx->sample_rate = in->rate;
            s->lavc_actx->bit_rate = bit_rate;

            if (avcodec_open2(s->lavc_actx, s->lavc_acodec, NULL) < 0) {
                MP_ERR(af, "Couldn't open codec %s, br=%d.\n", "ac3", bit_rate);
                return AF_ERROR;
            }

            if (s->lavc_actx->frame_size < 1) {
                MP_ERR(af, "encoder didn't specify input frame size\n");
                return AF_ERROR;
            }
        }
        s->in_samples = s->lavc_actx->frame_size;
        mp_audio_realloc(s->input, s->in_samples);
        s->input->samples = 0;
        s->encoder_buffered = 0;
        return AF_OK;
    }
    case AF_CONTROL_RESET:
        if (avcodec_is_open(s->lavc_actx))
            avcodec_flush_buffers(s->lavc_actx);
        talloc_free(s->pending);
        s->pending = NULL;
        s->input->samples = 0;
        s->encoder_buffered = 0;
        return AF_OK;
    }
    return AF_UNKNOWN;
}