Chris@0:
Chris@0:
Frequently Asked Questions
Chris@0:
Chris@0: Q1 : Is it normal for the output of libsamplerate to be louder
Chris@0: than its input?
Chris@0: Q2 : On Unix/Linux/MacOSX, what is the best way of detecting
Chris@0: the presence and location of libsamplerate and its header file using
Chris@0: autoconf?
Chris@0: Q3 : If I upsample and downsample to the original rate, for
Chris@0: example 44.1->96->44.1, do I get an identical signal as the one before the
Chris@0: up/down resampling?
Chris@0: Q4 : If I ran src_simple (libsamplerate) on small chunks (160
Chris@0: frames) would that sound bad?
Chris@0: Q5 : I'm using libsamplerate but the high quality settings
Chris@0: sound worse than the SRC_LINEAR converter. Why?
Chris@0: Q6 : I'm use the SRC_SINC_* converters and up-sampling by a ratio of
Chris@0: 2. I reset the converter and put in 1000 samples and I expect to get 2000
Chris@0: samples out, but I'm getting less than that. Why?
Chris@0: Q7 : I have input and output sample rates that are integer
Chris@0: values, but the API wants me to divide one by the other and put the result
Chris@0: in a floating point number. Won't this case problems for long running
Chris@0: conversions?
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Q1 : Is it normal for the output of libsamplerate to be louder
Chris@0: than its input?
Chris@0:
Chris@0: The output of libsamplerate will be roughly the same volume as the input.
Chris@0: However, even if the input is strictly in the range (-1.0, 1.0), it is still
Chris@0: possible for the output to contain peak values outside this range.
Chris@0:
Chris@0:
Chris@0: Consider four consecutive samples of [0.5 0.999 0.999 0.5].
Chris@0: If we are up sampling by a factor of two we need to insert samples between
Chris@0: each of the existing samples.
Chris@0: Its pretty obvious then, that the sample between the two 0.999 values should
Chris@0: and will be bigger than 0.999.
Chris@0:
Chris@0:
Chris@0: This means that anyone using libsamplerate should normalize its output before
Chris@0: doing things like saving the audio to a 16 bit WAV file.
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Q2 : On Unix/Linux/MacOSX, what is the best way of detecting
Chris@0: the presence and location of libsamplerate and its header file using
Chris@0: autoconf?
Chris@0:
Chris@0:
Chris@0: libsamplerate uses the pkg-config (man pkg-config) method of registering itself
Chris@0: with the host system.
Chris@0: The best way of detecting its presence is using something like this in configure.ac
Chris@0: (or configure.in):
Chris@0:
Chris@0:
Chris@0:
Chris@0: PKG_CHECK_MODULES(SAMPLERATE, samplerate >= 0.1.3,
Chris@0: ac_cv_samplerate=1, ac_cv_samplerate=0)
Chris@0:
Chris@0: AC_DEFINE_UNQUOTED([HAVE_SAMPLERATE],${ac_cv_samplerate},
Chris@0: [Set to 1 if you have libsamplerate.])
Chris@0:
Chris@0: AC_SUBST(SAMPLERATE_CFLAGS)
Chris@0: AC_SUBST(SAMPLERATE_LIBS)
Chris@0:
Chris@0:
Chris@0: This will automatically set the SAMPLERATE_CFLAGS and SAMPLERATE_LIBS
Chris@0: variables which can be used in Makefile.am or Makefile.in like this:
Chris@0:
Chris@0:
Chris@0: SAMPLERATE_CFLAGS = @SAMPLERATE_CFLAGS@
Chris@0: SAMPLERATE_LIBS = @SAMPLERATE_LIBS@
Chris@0:
Chris@0:
Chris@0:
Chris@0: If you install libsamplerate from source, you will probably need to set the
Chris@0: PKG_CONFIG_PATH environment variable's suggested at the end of the
Chris@0: libsamplerate configure process. For instance on my system I get this:
Chris@0:
Chris@0:
Chris@0: -=-=-=-=-=-=-=-=-=-= Configuration Complete =-=-=-=-=-=-=-=-=-=-=-
Chris@0:
Chris@0: Configuration summary :
Chris@0:
Chris@0: Version : ..................... 0.1.3
Chris@0: Enable debugging : ............ no
Chris@0:
Chris@0: Tools :
Chris@0:
Chris@0: Compiler is GCC : ............. yes
Chris@0: GCC major version : ........... 3
Chris@0:
Chris@0: Extra tools required for testing and examples :
Chris@0:
Chris@0: Have FFTW : ................... yes
Chris@0: Have libsndfile : ............. yes
Chris@0: Have libefence : .............. no
Chris@0:
Chris@0: Installation directories :
Chris@0:
Chris@0: Library directory : ........... /usr/local/lib
Chris@0: Program directory : ........... /usr/local/bin
Chris@0: Pkgconfig directory : ......... /usr/local/lib/pkgconfig
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Q3 : If I upsample and downsample to the original rate, for
Chris@0: example 44.1->96->44.1, do I get an identical signal as the one before the
Chris@0: up/down resampling?
Chris@0:
Chris@0: The short answer is that for the general case, no, you don't.
Chris@0: The long answer is that for some signals, with some converters, you will
Chris@0: get very, very close.
Chris@0:
Chris@0:
Chris@0: In order to resample correctly (ie using the SRC_SINC_* converters),
Chris@0: filtering needs to be applied, regardless of whether its upsampling or
Chris@0: downsampling.
Chris@0: This filter needs to attenuate all frequencies above 0.5 times the minimum of
Chris@0: the source and destination sample rate (call this fshmin).
Chris@0: Since the filter needed to achieve full attenuation at this point, it has to
Chris@0: start rolling off a some frequency below this point.
Chris@0: It is this rolloff of the very highest frequencies which causes some of the
Chris@0: loss.
Chris@0:
Chris@0:
Chris@0: The other factor is that the filter itself can introduce transient artifacts
Chris@0: which causes the output to be different to the input.
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Q4 : If I ran src_simple on small chunks (say 160 frames) would that
Chris@0: sound bad?
Chris@0:
Chris@0: Well if you are after odd sound effects, it might sound OK.
Chris@0: If you are after high quality sample rate conversion you will be disappointed.
Chris@0:
Chris@0:
Chris@0: The src_simple() was designed to provide a simple to use interface for people
Chris@0: who wanted to do sample rate conversion on say, a whole file all at once.
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Q5 : I'm using libsamplerate but the high quality settings
Chris@0: sound worse than the SRC_LINEAR converter. Why?
Chris@0:
Chris@0: There are two possible problems.
Chris@0: Firstly, if you are using the src_simple() function on successive blocks
Chris@0: of a stream of samples, you will get bad results. The src_simple() function
Chris@0: is designed for use on a whole sound file, all at once, not on contiguous
Chris@0: segments of the same sound file.
Chris@0: To fix the problem, you need to move to the src_process() API or the callback
Chris@0: based API.
Chris@0:
Chris@0:
Chris@0: If you are already using the src_process() API or the callback based API and
Chris@0: the high quality settings sound worse than SRC_LINEAR, then you have other
Chris@0: problems.
Chris@0: Read on for more debugging hints.
Chris@0:
Chris@0:
Chris@0: All of the higher quality converters need to keep state while doing conversions
Chris@0: on segments of a large chunk of audio.
Chris@0: This state information is kept inside the private data pointed to by the
Chris@0: SRC_STATE pointer returned by the src_new() function.
Chris@0: This means, that when you want to start doing sample rate conversion on a
Chris@0: stream of data, you should call src_new() to get a new SRC_STATE pointer
Chris@0: (or alternatively, call src_reset() on an existing SRC_STATE pointer).
Chris@0: You should then pass this SRC_STATE pointer to the src_process() function
Chris@0: with each new block of audio data.
Chris@0: When you have completed the conversion, you can then call src_delete() on
Chris@0: the SRC_STATE pointer.
Chris@0:
Chris@0:
Chris@0: If you are doing all of the above correctly, you need to examine your usage
Chris@0: of the values passed to src_process() in the
Chris@0: SRC_DATA
Chris@0: struct.
Chris@0: Specifically:
Chris@0:
Chris@0:
Chris@0: - Check that input_frames and output_frames fields are being set in
Chris@0: terms of frames (number of sample values times channels) instead
Chris@0: of just the number of samples.
Chris@0:
- Check that you are using the return values input_frames_used and
Chris@0: output_frames_gen to update your source and destination pointers
Chris@0: correctly.
Chris@0:
- Check that you are updating the data_in and data_out pointers
Chris@0: correctly for each successive call.
Chris@0:
Chris@0:
Chris@0: While doing the above, it is probably useful to compare what you are doing to
Chris@0: what is done in the example programs in the examples/ directory of the source
Chris@0: code tarball.
Chris@0:
Chris@0:
Chris@0: If you have done all of the above and are still having problems then its
Chris@0: probably time to email the author with the smallest chunk of code that
Chris@0: adequately demonstrates your problem.
Chris@0: This chunk should not need to be any more than 100 lines of code.
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Q6 : I'm use the SRC_SINC_* converters and up-sampling by a ratio of
Chris@0: 2. I reset the converter and put in 1000 samples and I expect to get 2000
Chris@0: samples out, but I'm getting less than that. Why?
Chris@0:
Chris@0: The short answer is that there is a transport delay inside the converter itself.
Chris@0: Long answer follows.
Chris@0:
Chris@0:
Chris@0: By way of example, the first time you call src_process() you might only get 1900
Chris@0: samples out.
Chris@0: However, after that first call all subsequent calls will probably get you about
Chris@0: 2000 samples out for every 1000 samples you put in.
Chris@0:
Chris@0:
Chris@0: The main problems people have with this transport delay is that they need to read
Chris@0: out an exact number of samples and the transport delay scews this up.
Chris@0: The best way to overcome this problem is to always supply more samples on the
Chris@0: input than is actually needed to create the required number of output samples.
Chris@0: With reference to the example above, if you always supply 1500 samples at the
Chris@0: input, you will always get 2000 samples at the output.
Chris@0: You will always need to keep track of the number of input frames used on each
Chris@0: call to src_process() and deal with these values appropriately.
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Q7 : I have input and output sample rates that are integer
Chris@0: values, but the API wants me to divide one by the other and put the result
Chris@0: in a floating point number. Won't this case problems for long running
Chris@0: conversions?
Chris@0:
Chris@0: The short answer is no, the precision of the ratio is many orders of magnitude
Chris@0: more than is really needed.
Chris@0:
Chris@0:
Chris@0: For the long answer, lets do come calculations.
Chris@0: Firstly, the src_ratio field is double precision floating point number
Chris@0: which has
Chris@0:
Chris@0: 53 bits of precision.
Chris@0:
Chris@0:
Chris@0: That means that the maximum error in your ratio converted to a double is one
Chris@0: bit in 2^53 which means the the double float value would be wrong by one sample
Chris@0: after 9007199254740992 samples have passed or wrong by more than half a sample
Chris@0: wrong after half that many (4503599627370496 samples) have passed.
Chris@0:
Chris@0:
Chris@0: Now if for example our output sample rate is 96kHz then
Chris@0:
Chris@0:
Chris@0: 4503599627370496 samples at 96kHz is 46912496118 seconds
Chris@0: 46912496118 seconds is 781874935 minutes
Chris@0: 781874935 minutes is 13031248 hours
Chris@0: 13031248 hours is 542968 days
Chris@0: 542968 days is 1486 years
Chris@0:
Chris@0:
Chris@0: So, after 1486 years, the input will be wrong by more than half of one sampling
Chris@0: period.
Chris@0:
Chris@0:
Chris@0: All this assumes that the crystal oscillators uses to sample the audio stream
Chris@0: is perfect.
Chris@0: This is not the case.
Chris@0: According to
Chris@0:
Chris@0: this web site,
Chris@0: the accuracy of standard crystal oscillators (XO, TCXO, OCXO) is at best
Chris@0: 1 in 100 million.
Chris@0: The src_ratio is therefore 45035996 times more accurate than the
Chris@0: crystal clock source used to sample the original audio signal and any potential
Chris@0: problem with the src_ratio being a floating point number will be
Chris@0: completely swamped by sampling inaccuracies.
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0: