diff options
| author | Jason Newton <nevion@gmail.com> | 2009-08-26 01:15:49 -0700 | 
|---|---|---|
| committer | Jason Newton <nevion@gmail.com> | 2009-10-02 02:14:20 -0700 | 
| commit | a434f4c6af1ba421f8c689fa8bf9e040268205b2 (patch) | |
| tree | 1688113226eacd3d32011da85165fe1fde0dc0ba | |
| parent | 3053badf0684e077fca8e8fddb43b4e9f2a5c30c (diff) | |
module-equalizer-sink: resyncing with head and fix invalid writes
    * pa_log->debug for default equalizer notification
    * partially fixed infinite rewind bug
    * set max_request to window_size first iteration
    * swap order inside ROUND_UP calls
    * resync pa_sink_input_new changes
    * change pa_sample_clamp parameters to be correct to fix invalid writes
    * reenable proper reset logic + proper request size
| -rwxr-xr-x | src/modules/module-equalizer-sink.c | 213 | 
1 files changed, 108 insertions, 105 deletions
diff --git a/src/modules/module-equalizer-sink.c b/src/modules/module-equalizer-sink.c index f634d5ea..f556be78 100755 --- a/src/modules/module-equalizer-sink.c +++ b/src/modules/module-equalizer-sink.c @@ -99,10 +99,10 @@ struct userdata {                * the latency of the filter, calculated from window_size                * based on constraints of COLA and window function                */ -    size_t latency;//Really just R but made into it's own variable      //for twiddling with pulseaudio      size_t overlap_size;//window_size-R      size_t samples_gathered; +    size_t input_buffer_max;      //message      float *W;//windowing function (time domain)      float *work_buffer, **input, **overlap_accum; @@ -198,6 +198,34 @@ static int is_monotonic(const uint32_t *xs,size_t length){      return 1;  } +//ensure's memory allocated is a multiple of v_size +//and aligned +static void * alloc(size_t x,size_t s){ +    size_t f = PA_ROUND_UP(x*s, sizeof(float)*v_size); +    float *t; +    pa_assert(f >= x*s); +    t = fftwf_malloc(f); +    memset(t, 0, f); +    return t; +} + +static void alloc_input_buffers(struct userdata *u, size_t min_buffer_length){ +    if(min_buffer_length <= u->input_buffer_max){ +        return; +    } +    pa_assert(min_buffer_length >= u->window_size); +    for(size_t c = 0; c < u->channels; ++c){ +        float *tmp = alloc(min_buffer_length, sizeof(float)); +        if(u->input[c]){ +            if(!u->first_iteration){ +                memcpy(tmp, u->input[c], u->overlap_size * sizeof(float)); +            } +            free(u->input[c]); +        } +        u->input[c] = tmp; +    } +    u->input_buffer_max = min_buffer_length; +}  /* Called from I/O thread context */  static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { @@ -359,7 +387,7 @@ static void dsp_logic(      //preseve the needed input for the next window's overlap      memmove(src, src + u->R, -        u->overlap_size * sizeof(float) +        (u->samples_gathered - u->R) * sizeof(float)      );  } @@ -470,71 +498,64 @@ typedef union float_vector {  //}  static void process_samples(struct userdata *u, pa_memchunk *tchunk){ -    size_t fs=pa_frame_size(&(u->sink->sample_spec)); +    size_t fs = pa_frame_size(&(u->sink->sample_spec));      float *dst;      unsigned a_i;      float *H, X; -    pa_assert(u->samples_gathered >= u->R); +    size_t iterations, offset; +    pa_assert(u->samples_gathered >= u->window_size); +    iterations = (u->samples_gathered - u->overlap_size) / u->R;      tchunk->index = 0; -    tchunk->length = u->R * fs; +    tchunk->length = iterations * u->R * fs;      tchunk->memblock = pa_memblock_new(u->sink->core->mempool, tchunk->length); -    dst = ((float*)pa_memblock_acquire(tchunk->memblock)); - -    for(size_t c=0;c < u->channels; c++) { -        a_i = pa_aupdate_read_begin(u->a_H[c]); -        X = u->Xs[c][a_i]; -        H = u->Hs[c][a_i]; -        dsp_logic( -            u->work_buffer, -            u->input[c], -            u->overlap_accum[c], -            X, -            H, -            u->W, -            u->output_window, -            u -        ); -        pa_aupdate_read_end(u->a_H[c]); -        if(u->first_iteration){ -            /* The windowing function will make the audio ramped in, as a cheap fix we can -             * undo the windowing (for non-zero window values) -             */ -            for(size_t i = 0;i < u->overlap_size; ++i){ -                u->work_buffer[i] = u->W[i] <= FLT_EPSILON ? u->work_buffer[i] : u->work_buffer[i] / u->W[i]; +    dst = ((float*) pa_memblock_acquire(tchunk->memblock)); +    for(size_t iter = 0; iter < iterations; ++iter){ +        offset = iter * u->R * fs; +        for(size_t c = 0;c < u->channels; c++) { +            a_i = pa_aupdate_read_begin(u->a_H[c]); +            X = u->Xs[c][a_i]; +            H = u->Hs[c][a_i]; +            dsp_logic( +                u->work_buffer, +                u->input[c], +                u->overlap_accum[c], +                X, +                H, +                u->W, +                u->output_window, +                u +            ); +            pa_aupdate_read_end(u->a_H[c]); +            if(u->first_iteration){ +                /* The windowing function will make the audio ramped in, as a cheap fix we can +                 * undo the windowing (for non-zero window values) +                 */ +                for(size_t i = 0; i < u->overlap_size; ++i){ +                    u->work_buffer[i] = u->W[i] <= FLT_EPSILON ? u->work_buffer[i] : u->work_buffer[i] / u->W[i]; +                }              } +            pa_sample_clamp(PA_SAMPLE_FLOAT32NE, (uint8_t *) (dst + c) + offset, fs, u->work_buffer, sizeof(float), u->R);          } -        pa_sample_clamp(PA_SAMPLE_FLOAT32NE, dst + c, fs, u->work_buffer, sizeof(float), u->R); +        if(u->first_iteration){ +            u->first_iteration = FALSE; +        } +        u->samples_gathered -= u->R;      }      pa_memblock_release(tchunk->memblock); -    u->samples_gathered -= u->R; -} - -static void initialize_buffer(struct userdata *u, pa_memchunk *in){ -    size_t fs = pa_frame_size(&u->sink->sample_spec); -    size_t samples = in->length / fs; -    float *src = (float*) ((uint8_t*) pa_memblock_acquire(in->memblock) + in->index); -    pa_assert_se(u->samples_gathered + samples <= u->window_size); -    for(size_t c = 0; c < u->channels; c++) { -        //buffer with an offset after the overlap from previous -        //iterations -        pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input[c] + u->samples_gathered, sizeof(float), src + c, fs, samples); -    } -    u->samples_gathered += samples; -    pa_memblock_release(in->memblock);  }  static void input_buffer(struct userdata *u, pa_memchunk *in){      size_t fs = pa_frame_size(&(u->sink->sample_spec));      size_t samples = in->length/fs;      float *src = (float*) ((uint8_t*) pa_memblock_acquire(in->memblock) + in->index); -    pa_assert_se(samples <= u->window_size - u->samples_gathered); +    pa_assert(u->samples_gathered + samples <= u->input_buffer_max);      for(size_t c = 0; c < u->channels; c++) {          //buffer with an offset after the overlap from previous          //iterations          pa_assert_se( -            u->input[c]+u->samples_gathered+samples <= u->input[c]+u->window_size +            u->input[c] + u->samples_gathered + samples <= u->input[c] + u->input_buffer_max          ); -        pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input[c]+u->samples_gathered, sizeof(float), src + c, fs, samples); +        pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input[c] + u->samples_gathered, sizeof(float), src + c, fs, samples);      }      u->samples_gathered += samples;      pa_memblock_release(in->memblock); @@ -543,7 +564,7 @@ static void input_buffer(struct userdata *u, pa_memchunk *in){  /* Called from I/O thread context */  static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {      struct userdata *u; -    size_t fs; +    size_t fs, target_samples;      struct timeval start, end;      pa_memchunk tchunk;      pa_sink_input_assert_ref(i); @@ -551,6 +572,16 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk      pa_assert(chunk);      pa_assert(u->sink);      fs = pa_frame_size(&(u->sink->sample_spec)); +    target_samples = PA_ROUND_UP(nbytes / fs, u->R); +    if(u->first_iteration){ +        //allocate request_size +        target_samples = PA_MAX(target_samples, u->window_size); +    }else{ +        //allocate request_size + overlap +        target_samples += u->overlap_size; +        alloc_input_buffers(u, target_samples); +    } +    alloc_input_buffers(u, target_samples);      chunk->memblock = NULL;      /* Hmm, process any rewind request that might be queued up */ @@ -559,18 +590,11 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk      //pa_log_debug("start output-buffered %ld, input-buffered %ld, requested %ld",buffered_samples,u->samples_gathered,samples_requested);      pa_rtclock_get(&start);      do{ -        size_t input_remaining = u->window_size - u->samples_gathered; +        size_t input_remaining = target_samples - u->samples_gathered;          pa_assert(input_remaining > 0); -        //collect samples - -        //buffer = &u->conv_buffer; -        //buffer->length = input_remaining*fs; -        //buffer->index = 0; -        //pa_memblock_ref(buffer->memblock); -        //pa_sink_render_into(u->sink, buffer);          while(pa_memblockq_peek(u->input_q, &tchunk) < 0){ -            pa_sink_render(u->sink, input_remaining*fs, &tchunk); -            //pa_sink_render_full(u->sink, input_remaining*fs, &tchunk); +            //pa_sink_render(u->sink, input_remaining * fs, &tchunk); +            pa_sink_render_full(u->sink, input_remaining * fs, &tchunk);              pa_assert(tchunk.memblock);              pa_memblockq_push(u->input_q, &tchunk);              pa_memblock_unref(tchunk.memblock); @@ -581,15 +605,12 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk          //pa_log_debug("asked for %ld input samples, got %ld samples",input_remaining,buffer->length/fs);          /* copy new input */          //pa_rtclock_get(start); -        if(u->first_iteration){ -            initialize_buffer(u, &tchunk); -        }else{ -            input_buffer(u, &tchunk); -        } +        input_buffer(u, &tchunk);          //pa_rtclock_get(&end);          //pa_log_debug("Took %0.5f seconds to setup", pa_timeval_diff(end, start) / (double) PA_USEC_PER_SEC);          pa_memblock_unref(tchunk.memblock); -    }while(u->samples_gathered < u->window_size); +    }while(u->samples_gathered < target_samples); +      pa_rtclock_get(&end);      pa_log_debug("Took %0.6f seconds to get data", (double) pa_timeval_diff(&end, &start) / PA_USEC_PER_SEC); @@ -605,9 +626,6 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk      pa_assert(chunk->memblock);      //pa_log_debug("gave %ld", chunk->length/fs);      //pa_log_debug("end pop"); -    if(u->first_iteration){ -        u->first_iteration = FALSE; -    }      return 0;  } @@ -632,11 +650,17 @@ static void sink_input_mute_changed_cb(pa_sink_input *i) {  }  static void reset_filter(struct userdata *u){ +    size_t fs = pa_frame_size(&u->sink->sample_spec); +    size_t max_request;      u->samples_gathered = 0; -    for(size_t i = 0;i < u->channels; ++i){ +    for(size_t i = 0; i < u->channels; ++i){          memset(u->overlap_accum[i], 0, u->overlap_size * sizeof(float));      }      u->first_iteration = TRUE; +    //set buffer size to max request, no overlap copy +    max_request = PA_ROUND_UP(pa_sink_input_get_max_request(u->sink_input) / fs , u->R); +    max_request = PA_MAX(max_request, u->window_size); +    pa_sink_set_max_request_within_thread(u->sink, max_request * fs);  }  /* Called from I/O thread context */ @@ -658,11 +682,8 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {          u->sink->thread_info.rewind_nbytes = 0;          if (amount > 0) { -            //pa_sample_spec *ss = &u->sink->sample_spec;              //invalidate the output q              pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE); -            //pa_memblockq_drop(u->input_q, pa_memblockq_get_length(u->input_q)); -            //pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);              pa_log("Resetting filter");              reset_filter(u);          } @@ -689,11 +710,11 @@ static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {      size_t fs;      pa_sink_input_assert_ref(i);      pa_assert_se(u = i->userdata); - +    //if(u->first_iteration){ +    //    return; +    //}      fs = pa_frame_size(&(u->sink->sample_spec)); -    //pa_sink_set_max_request_within_thread(u->sink, nbytes); -    //pa_sink_set_max_request_within_thread(u->sink, u->R*fs); -    pa_sink_set_max_request_within_thread(u->sink, ((nbytes+u->R*fs-1)/(u->R*fs))*(u->R*fs)); +    pa_sink_set_max_request_within_thread(u->sink, PA_ROUND_UP(nbytes / fs, u->R) * fs);  }  /* Called from I/O thread context */ @@ -703,8 +724,6 @@ static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {      pa_sink_input_assert_ref(i);      pa_assert_se(u = i->userdata); -    //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->latency*fs); -    //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->latency*fs );      pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);  } @@ -733,7 +752,7 @@ static void sink_input_detach_cb(pa_sink_input *i) {  /* Called from I/O thread context */  static void sink_input_attach_cb(pa_sink_input *i) {      struct userdata *u; -    size_t fs; +    size_t fs, max_request;      pa_sink_input_assert_ref(i);      pa_assert_se(u = i->userdata); @@ -741,19 +760,15 @@ static void sink_input_attach_cb(pa_sink_input *i) {      pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);      pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency); -    fs = pa_frame_size(&(u->sink->sample_spec)); -    pa_sink_set_max_request_within_thread(u->sink, PA_ROUND_UP(pa_sink_input_get_max_request(i), u->R*fs)); - -    //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->latency*fs); -    //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->master->thread_info.max_latency); -    //TODO: setting this guy minimizes drop outs but doesn't get rid -    //of them completely, figure out why -    //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->latency*fs); -    //TODO: this guy causes dropouts constantly+rewinds, it's unusable -    //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->master->thread_info.max_latency); +    fs = pa_frame_size(&u->sink->sample_spec); +    //set buffer size to max request, no overlap copy +    max_request = PA_ROUND_UP(pa_sink_input_get_max_request(u->sink_input) / fs , u->R); +    max_request = PA_MAX(max_request, u->window_size); +    pa_sink_set_max_request_within_thread(u->sink, max_request * fs); +    pa_sink_set_max_rewind_within_thread(u->sink, pa_sink_input_get_max_rewind(i));      pa_sink_attach_within_thread(u->sink);      if(u->set_default){ -        pa_log("Setting default sink to %s", u->sink->name); +        pa_log_debug("Setting default sink to %s", u->sink->name);          pa_namereg_set_default_sink(u->module->core, u->sink);      }  } @@ -1005,17 +1020,6 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {          pa_sink_set_asyncmsgq(u->sink, NULL);  } -//ensure's memory allocated is a multiple of v_size -//and aligned -static void * alloc(size_t x,size_t s){ -    size_t f = PA_ROUND_UP(x*s, sizeof(float)*v_size); -    float *t; -    pa_assert(f >= x*s); -    t = fftwf_malloc(f); -    memset(t, 0, f); -    return t; -} -  int pa__init(pa_module*m) {      struct userdata *u;      pa_sample_spec ss; @@ -1068,15 +1072,15 @@ int pa__init(pa_module*m) {      u->R = (u->window_size + 1) / 2;      u->overlap_size = u->window_size - u->R;      u->samples_gathered = 0; +    u->input_buffer_max = 0;      u->a_H = pa_xnew0(pa_aupdate *, u->channels); -    u->latency = u->window_size - u->R;      u->Xs = pa_xnew0(float *, u->channels);      u->Hs = pa_xnew0(float **, u->channels);      for(size_t c = 0; c < u->channels; ++c){          u->Xs[c] = pa_xnew0(float, 2);          u->Hs[c] = pa_xnew0(float *, 2);          for(size_t i = 0; i < 2; ++i){ -            u->Hs[c][i] = alloc((FILTER_SIZE), sizeof(float)); +            u->Hs[c][i] = alloc(FILTER_SIZE, sizeof(float));          }      }      u->W = alloc(u->window_size, sizeof(float)); @@ -1086,8 +1090,7 @@ int pa__init(pa_module*m) {      u->overlap_accum = pa_xnew0(float *, u->channels);      for(size_t c = 0; c < u->channels; ++c){          u->a_H[c] = pa_aupdate_new(); -        u->input[c] = alloc(u->window_size, sizeof(float)); -        memset(u->input[c], 0, (u->window_size)*sizeof(float)); +        u->input[c] = NULL;          u->overlap_accum[c] = alloc(u->overlap_size, sizeof(float));          memset(u->overlap_accum[c], 0, u->overlap_size*sizeof(float));      } @@ -1151,7 +1154,7 @@ int pa__init(pa_module*m) {      pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);      pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); -    pa_sink_input_new(&u->sink_input, m->core, &sink_input_data, 0); +    pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);      pa_sink_input_new_data_done(&sink_input_data);      if (!u->sink_input)  | 
