Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calculate in advance the number of samples needed for generating a fixed size #175

Open
scjurgen opened this issue Jan 13, 2022 · 5 comments
Labels

Comments

@scjurgen
Copy link

scjurgen commented Jan 13, 2022

Is there any (easy) possibility to obtain in advance the samples needed for generating a certain amount of data?
e.g.: Convert from 48000 to 44100 with SINC.
To obtain 64 samples I need to feed i.e. 69 or 70 samples (a sequence like 70,69,70,70,69,70,70).
I would like to know in advance how many samples I actually have to provide to obtain deterministic 64 samples without having too much buffering going on in the sinc filter it self.
This would save some buffering overhead in a host application and is needed to maintain parallel control data to the sample data in realtime applications. I know that I can obtain usable data by peeking into the filter:

   SINC_FILTER *sinc =  (SINC_FILTER *) state->private_data;  
   int buffered = sinc->b_end - sinc->b_current;  
   int delay = sinc->coeff_half_len / (sinc->index_inc * (state->last_ratio < 1.0 ? state->last_ratio : 1.0)). 
@evpobr
Copy link
Member

evpobr commented Jan 13, 2022

Hi @scjurgen . @SoapGentoo , @arthurt, do you have any ideas?

@arlofaria
Copy link

If the internal SRC state is currently unbuffered, then perhaps this is the answer:

int required_input_samples = round(desired_output_samples / src_ratio)

This would seem to match the observed pattern you provided for the first few blocks of 64 output samples. Note that it's independent of the size of the sinc filter.

As noted in similar discussion in #6, I'm not confident in my understanding of this since the source code is a bit intimidating.

@scjurgen
Copy link
Author

Thanks to a thread here on github by @arlofaria I started looking deeper into the implementation and
I did a patch today that tests ok. I needed only to expose some information from SINC_FILTER

// in src_sinc.c:
 
int sinc_get_input_delay(const SRC_STATE *state) 
{
    SINC_FILTER *sinc =  (SINC_FILTER *) state->private_data;
    return sinc->coeff_half_len / (sinc->index_inc * (state->last_ratio < 1.0 ? state->last_ratio : 1.0));
}

// calculate current remaining data in buffer
int sinc_get_buffererd(const SRC_STATE *state)
{
    SINC_FILTER *sinc =  (SINC_FILTER *) state->private_data;
    int delta = sinc->b_end - sinc->b_current;
    if (delta < 0) // not sure this ever happened, looks like handled in prepare_data
        delta += sinc->b_len;
    return delta;
}

I used it than like this (fixed ratio only):

   // init
   int maxBuffered = sinc_get_input_delay(src) + ceil(ratio) + 1; // needs to be called after feeding some data to src_process
   // ...
   // in a processing loop I can now calculate the data needed:
   int produceSamplesCount = frameSize / ratio + 1;
   int buffered = sinc_get_buffererd(src); // peek into the buffer count
   if (buffered > maxBuffered) // buffer is filling up, we provide one sample less
         produceSamplesCount -= 1;
   // produceSamplesCount is the number of samples I need to provide for SRC_DATA
   // to obtain exactly frameSize

I tested this for all 3 SINC's and for various ratios and framesize. Some still have problems with not consuming all input data due to the handling in prepare_data where it loads data at the current end position.

@scjurgen
Copy link
Author

Hi @arlofaria

I started with your approach, but soon I realised that the handling is a bit more complex. Your answer in the other thread was helpful to dig into it.

If the internal SRC state is currently unbuffered, then perhaps this is the answer:

int required_input_samples = round(desired_output_samples / src_ratio)

@arlofaria
Copy link

Nice! Great to see that someone is willing to dig deeper into this :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants