From 76288efeead86fd5799d9771e50bf3222aaa8e71 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sun, 3 Nov 2019 15:36:47 +0100 Subject: Import from zita-resampler-1.6.0.tar.bz2 --- docs/filt1.png | Bin 0 -> 9528 bytes docs/filt2.png | Bin 0 -> 3117 bytes docs/inpdist.png | Bin 0 -> 14940 bytes docs/resampler.html | 574 ++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/src-1kHz.png | Bin 0 -> 34429 bytes docs/zita-1kHz.png | Bin 0 -> 34459 bytes docs/zitadocs.css | 18 ++ 7 files changed, 592 insertions(+) create mode 100644 docs/filt1.png create mode 100644 docs/filt2.png create mode 100644 docs/inpdist.png create mode 100644 docs/resampler.html create mode 100644 docs/src-1kHz.png create mode 100644 docs/zita-1kHz.png create mode 100644 docs/zitadocs.css (limited to 'docs') diff --git a/docs/filt1.png b/docs/filt1.png new file mode 100644 index 0000000..0fdd30c Binary files /dev/null and b/docs/filt1.png differ diff --git a/docs/filt2.png b/docs/filt2.png new file mode 100644 index 0000000..4a5bf5b Binary files /dev/null and b/docs/filt2.png differ diff --git a/docs/inpdist.png b/docs/inpdist.png new file mode 100644 index 0000000..5a89018 Binary files /dev/null and b/docs/inpdist.png differ diff --git a/docs/resampler.html b/docs/resampler.html new file mode 100644 index 0000000..eb608e0 --- /dev/null +++ b/docs/resampler.html @@ -0,0 +1,574 @@ + + + + Zita-resampler. + + + + + + + + + +

Libzita-resampler

+ + +
+ +

Introduction

+

+Libzita-resampler is a C++ library for resampling audio signals. It is designed +to be used within a real-time processing context, to be fast, and to provide +high-quality sample rate conversion. +

+

+The library operates on signals represented in single-precision floating point +format. For multichannel operation both the input and output signals are +assumed to be stored as interleaved samples. +

+

+The API allows a trade-off between quality and CPU load. For the latter +a range of approximately 1:6 is available. Even at the highest quality +setting libzita-resampler will be faster than most similar libraries +providing the same quality, e.g. libsamplerate. +

+

+In many real-time resampling applications (e.g. an audio player), processing +is driven by the ouput sample rate: each processing period requires a fixed +number of output samples, and the input side has to adapt, providing whatever +number of samples required. The inverse situation (less common, but possible) +would be e.g. a recording application that writes an audio file at a rate that +is different from the hardware sample rate. In that case the number of input +samples is fixed for each processing period. The API provided by libzita-resampler +is fully symmetric in this respect - it handles both situations in the exactly the +same way, using the same application code. +

+

+Libzita-resampler provides two classes: +

+

+The Resampler class performs resampling at a fixed ratio F_out / F_in +which is required to be ≥ 1/16 and be reducible to the form b / a +with a, b integer and b ≤ 1000. This includes all the 'standard' +ratios, e.g. 96000 / 44100 = 320 / 147. These restrictions allow for a more efficient +implementation. +

+

+The VResampler class provides an arbitrary ratio r in the range +1/16 ≤ r ≤ 64 and which can variable within a range of 0.95 to +16.0 w.r.t. the originally configured one. The lower limit here is necessary +because this class still uses a fixed multiphase filter, with only the phase step +being variable. This class was developed for converting between two nominally fixed +sample rates with a ratio which is not known exactly and may even drift slowly, e.g. +when combining sound cards wich do not have a common word clock. This resampler is +somewhat less efficient than the fixed ratio one since it has to interpolate filter +coefficients, but the difference is marginal when used on multichannel signals. +

+

+Both classes provide essentially the same API, with only small differences +where necessary. + +
+ +

The algorithm

+

+Libzita-resampler implements constant bandwidth resampling. In contrast +to e.g. cubic interpolation it does not consider the actual shape of the +waveform represented by the input samples, but rather operates in the spectral +domain. +

+

+Let +

+

+Then the calculation performed by zita-resampler is equivalent to: +

+ +

+This is of course not how things are implemented in the resampler code. +Only those samples that are actually output are computed, and the inserted +zeros are never used. In practice this means there is a set of b +different FIR filters that each output one sample in turn, in round-robin +fashion. All these filters have the same frequency response, but different +delays that correspond to the relative position in time of the input and +output samples. +

+

+A real-world filter can't be perfect, it is always a compromise between +complexity (CPU load) and performance. In the context of resampling this +compromise manifests itself as deviations from the ideally flat frequency +response, and as aliasing - the same phenomenon that occurs with AD and +DA conversion. For aliasing, two cases need to be considered: +

+

+Upsampling. In this case F_min = F_in, and input signals +below but near to F_in / 2 will also appear in the output +just above this frequency. This is similar to DA conversion. +

+

+Downsampling. In this case F_min = F_out, and input signals +above but near to F_out / 2 will also appear in the output +just below this frequency. This is similar to AD conversion. +

+

+In the design of zita-resampler it was assumed that in most cases +conversion will be between the 'standard' audio sample rates (44.1, +48, 88.2, 96, 192 kHz), and that consequently frequency response +errors and aliasing will occur only above the upper limit of the +audible frequency range. Given this assumption, some pragmatic +trade-offs can be made. +

+

+The filter used by libzita-resampler is dimensioned to reach an +attenuation of 60dB at the Nyquist frequency. The initialisation +function takes a parameter named hlen that is in fact half +the length of the symmetrical FIR filter expressend in samples at +the rate F_min. The valid range for hlen is 16 to 96. +The figure below shows the filter responses for hlen = 32, +48, and 96. The x axis is F / F_min, the y axis +is in dB. The lower part of the traces is the mirrored continuation +of the response above the Nyquist frequency, i.e. the aliasing. +Note that 20 kHz corresponds to x = 0.416 for a sample rate of 48 kHz, +and to x = 0.454 for a sample rate of 44.1 kHz. +

+

+ +

+

+
+The same traces with a reduced vertical range, showing the passband +response. +

+

+ +

+

+From these figures it should be clear that hlen = 32 should +provide very high quality for F_min equal to 48 kHz or higher, +while hlen = 48 should be sufficient for an F_min of +44.1 kHz. The validity of these assumptions was confirmed by a series +of listening tests. If fact the conclusion of these test was that even +at 44.1 kHz the subjects (all audio specialists or musicians) could not +detect any significant difference between hlen values of 32 and 96. +

+ +
+ +

API description

+

+The constructors of both classes do not initialise the object for a particular +resampling rate, quality or number of channels - this is done by a separate +function member which can be used as many times as necessary. This means you +can allocate (V)Resampler objects before the actual resampling parameters +are known. +

+

+The setup () member initialises a resampler for a combination of input +sample rate, output sample rate, number of channels, and filter length. This +function allocates and computes the filter coefficient tables and is definitely +not RT-safe. The actual tables will be shared with other resampler instances if +possible - the library maintains a reference-counted collection of them. After +the initialisation by setup (), the process () member can be called +repeatedly to actually resample audio signals. This function is RT-safe and +can be used within e.g. a JACK callback. The clear () member restores +the object to the initial state it has after construction, and is also called +from the destructor. You can safely call setup () again without first +calling clear () - doing this avoids recomputation of the filter +coefficients in some cases. +

+

+Both classes have four public data members which are used as input and output +parameters of process (), in the same way as you would use a C struct +to pass parameters. These are: +

+
+      unsigned int     inp_count;   // number of frames in the input buffer
+      unsigned int     out_count;   // number of frames in the output buffer
+      float           *inp_data;    // pointer to first input frame
+      float           *out_data;    // pointer to first output frame
+
+

+As process () does its work, it increments the pointers and decrements the +counts. The call returns when either of the counts is zero, i.e. when the input +buffer is empty or the output buffer is full. You should then take appropriate +action and if necessary call process () again. +

+

+When process () returns, the four parameter values exactly reflect +those parts of both buffers that have not yet been used. +One of them will be fully used, with the corresponding count being zero. +The remaining part of the other, pointed to by the returned pointer, can +always be replaced before the next call to process (), but this is +entirely optional. +

+

+When for example inp_count is zero, you have to fill the input buffer +again, or provide a new one, and re-initialise the input count and pointer. +If at that time out_count is not zero, you can either leave the output +parameters as they are for the next call to process (), or you could +empty the part of the output buffer that has been filled and re-use it from +the start, or provide a completely different one. +

+

+The same applies to the input buffer when it is not empty on return of +process (): it can be left alone or be replaced. A number of input +samples is stored internally between process () calls as part of the +resampler state, but this never includes samples that have not yet been used. +So you can 'revise' the input data, starting from the frame pointed to by the +returned inp_data, up to the last moment. +

+

+All this means that both classes will interface easily with fixed input and +output buffers, with dynamically generated input signals, and also with +lock-free circular buffers. +

+

+Either of the two pointers can be NULL. When inp_data is zero, the effect +is to insert zero-valued input samples, as if you had supplied a zero-filled +buffer of length inp_count. When out_data is zero, input samples +will be consumed, the internal state of the resampler will advance normally +and out_count will decrement, but no output samples are written (in +fact they are not even computed). +

+ +

+Note that libzita-resampler does not automatically insert zero-valued +input samples at the start and end of the resampling process. The API makes it +easy to add such padding, and doing this is left entirely up to the user. +

+

+The inpsize () member returns the lenght of the FIR filter expressed in +input samples. At least this number of samples is required to produce an output +sample. If k is the value returned by this function, then +

+ +

+Similar considerations apply at the end of the input data: +

+ +

+ +The inpdist () member returns the distance or delay expressed in sample +periods at the input rate, between the first output sample that will be ouput +by the next call to process () and the first input sample that will be +read (i.e. that is not yet part of the internal state). +

+In the picture below, the red dots represent input samples and the blue ones +are the output. Solid dots are samples already used or output. After a call +to process () the resampler object remains in a state ready to produce the next +output sample, except that it may have to input one or more new samples first. +The filter is aligned with the next output sample. In this case one more input +sample is required to compute it, and the input distance is 2.7. +

+

+ +

+

+After a resampler is prefilled with inpsize () / 2 - 1 samples as described +above, inpdist () will be zero - the first output sample corresponds exactly +to the first input. Note that without prefilling the distance is negative, which +means that the first output sample corresponds to some point past the start of the +input data. +

+

+The 'resample' application supplied with the library sources provides +an example of how to use the Resampler class. For an example +using VResampler you can have a look at zita_a2j and zita_ja2. +

+ +
+ +

API reference

+

+Public function members of the Resampler and VResampler classes. +Functions listed without a class prefix are available for both classes. +

+ +

+Public data members of the Resampler and VResampler classes. +

+ + + +

Resampler (void);
~Resampler (void);

+

+Description: Constructor and destructor. The constructor just creates an object that takes +almost no memory but needs to be configured by setup () before it +can be used. The destructor calls clear (). +

+RT-safe: No +

+ + +

VResampler (void);
~VResampler (void);

+

+Description: Constructor and destructor. The constructor just creates an object that takes +almost no memory but needs to be configured by setup () before it +can be used. The destructor calls clear (). +

+RT-safe: No +

+ + +

int   Resampler::setup (unsigned int   fs_inp, unsigned int fs_out, unsigned int nchan, unsigned int hlen);

+

+Description: Configures the object for a combination of input / output sample rates, number +of channels, and filter lenght.
If the parameters are OK, creates the filter coefficient tables +or re-uses existing ones, allocates some internal resources, and returns via +reset (). +

+Parameters: +

+

+fs_inp, fs_out: The input and output sample rates. The ratio fs_out +/ fs_inp must be ≥ 1/16 and reducible to the form b / a +with a, b integer and b ≤ 1000. +

+nchan: Number of channels, must not be zero. +

+hlen: Half the lenght of the filter expressed in samples at the lower of +input and output rates. This parameter determines the 'quality' as explained +here. For any fixed combination of the other parameters, +cpu load will be roughly proportional to hlen. The valid range is +16 ≤ hlen ≤ 96. +

+

+Returns: Zero on success, non-zero otherwise. +

+Remark: It is perfectly safe to call this function again without +having called clear () first. If only the number +of channels is changed, doing this will avoid recalculation of the filter tables +even if they are not shared. +

+RT-safe: No +

+ + +

int   VResampler::setup (double ratio, unsigned int nchan, unsigned int hlen);

+

+Description: Configures the object for a combination of resampling ratio, number of channels, +and filter lenght.
If the parameters are OK, creates the filter coefficient tables or re-uses +existing ones, allocates some internal resources, and returns via +reset (). +

+Parameters: +

+

+ratio: The resampling ratio wich must be between 1/16 and 64. +

+nchan: Number of channels, must not be zero. +

+hlen: Half the lenght of the filter expressed in samples at the lower of +the input and output rates. This parameter determines the 'quality' as explained +here. For any fixed combination of the other parameters, +cpu load will be roughly proportional to hlen. The valid range is +16 ≤ hlen ≤ 96. +

+

+Returns: Zero on success, non-zero otherwise. +

+Remark: It is perfectly safe to call this function again without +having called clear () first. If only the number +of channels is changed, doing this will avoid recalculation of the filter tables +even if they are not shared. +

+RT-safe: No +

+ + +

void   clear (void);

+

+Description: Deallocates resources (if not shared) and returns the object to +the unconfigured state as after construction. Also called by the destructor. +

+RT-safe: No +

+ + +

int   reset (void);

+

+Description: Resets the internal state of the resampler. Any stored +input samples are cleared, the filter phase and the four +public data members are set to zero. This should be called before starting +resampling a new stream with the same configuration as the previous one. +

+Returns: Zero if the resampler is configured , non-zero otherwise. +

+RT-safe: Yes. +

+ + +

int   process (void);

+

+Description: Resamles the input signal until either the input buffer +is empty or the output buffer is full. Information on the input and output +buffers is passed to this function using the four public +data members described below. The same four values are updated on return. +

+Returns: Zero if the resampler is configured, non-zero otherwise. +

+RT-safe: Yes. +

+ + +

int   nchan (void);

+

+Description: Accessor. +

+Returns: The number of channels the resampler is configured for, +or zero if it is unconfigured. Input and output buffers are assumed to contain +this number of channels in interleaved format. +

+RT-safe: Yes +

+ + +

int   inpisze (void);

+

+Description: Accessor. +

+Returns: If the resampler is configured, the lenght of the +finite impulse filter expressed in samples at the input sample rate, +or zero otherwise. This value may be used to determine the number of +silence samples to insert at the start and end when resampling e.g. +an impulse response. See here for more about this. +This function was called 'filtlen ()' in previous releases. +

+RT-safe: Yes +

+ + +

double   inpdist (void);

+

+Description: Accessor. +

+Returns: If the resampler is configured, the distance between +the next output sample and the next input sample, expressed in sample +periods at the input rate, zero otherwise. See +here for more about this. +

+RT-safe: Yes +

+ + +

void   VResampler::set_rratio (double ratio);

+

+Description: Sets the resampling ratio relative to the one configured +by setup (). The valid range is 0.95 ≤ +ratio ≤ 16. +

+Parameters: +

+

+ratio: The relative resampling ratio. +

+

+RT-safe: Yes +

+ + +

void   VResampler::set_rrfilt (double time);

+

+Description: Sets the time constant of the first order filter applied +on values set by set_rratio (). The time is +expressed as sample periods at the output rate. The default is zero, which +means changes are applied instantly. +

+Parameters: +

+

+time: The filter time constant. +

+

+RT-safe: Yes +

+ + +

unsigned int   inp_count;

+

+Description: Data member, input / output parameter of the +process () function. This value is always equal to the number of frames in the +input buffer that have not yet been read by the process () function. It should be set +to the number of available frames before calling process (). +

+ + +

unsigned int   out_count;

+

+Description: Data member, input / output parameter of the +process () function. This value is always equal to the number of frames in the +output buffer that have not yet been written by the process () function. It should be +set to the size of the output buffer before calling process (). +

+ + +

float   *inp_data;

+

+Description: Data member, input / output parameter of the +process () function. If not zero (NULL), this points to the next frame in the +input buffer that will be read by process (). If set to zero (NULL), the resampler +will proceed normally but use zero-valued samples as input (still counted by +inp_count). +

+ + +

float   *out_data;

+

+Description: Data member, input / output parameter of the +process () function. If not zero (NULL), this points to the next frame in the +output buffer that will be written by process (). If set to zero (NULL), the resampler +will proceed normally but the output is discarded (but still counted by out_count). +

+ + + diff --git a/docs/src-1kHz.png b/docs/src-1kHz.png new file mode 100644 index 0000000..18b450a Binary files /dev/null and b/docs/src-1kHz.png differ diff --git a/docs/zita-1kHz.png b/docs/zita-1kHz.png new file mode 100644 index 0000000..4028fa4 Binary files /dev/null and b/docs/zita-1kHz.png differ diff --git a/docs/zitadocs.css b/docs/zitadocs.css new file mode 100644 index 0000000..8afb88d --- /dev/null +++ b/docs/zitadocs.css @@ -0,0 +1,18 @@ +body { background: white; color: black; font-family: arial, helvetica, sans-serif; } +center { font-family: arial, helvetica, sans-serif; } +p { font-family: arial, helvetica, sans-serif; text-align: left; margin-left: 3%; margin-right: 3%; } +td { font-family: arial, helvetica, sans-serif; background: white; color: black; } +ul { font-family: arial, helvetica, sans-serif; text-align: left; margin-left: 3%; margin-right: 6%; } +ol { font-family: arial, helvetica, sans-serif; text-align: left; margin-left: 3%; margin-right: 6%; } +dl { font-family: arial, helvetica, sans-serif; text-align: left; margin-left: 3%; margin-right: 3%; } +h1 { font-size: xx-large; background: #8080FF; color: white; text-align: left; padding-left: 20; } +h2 { font-size: x-large; background: #8080FF; color: white; text-align: left; padding-left: 20; } +h3 { font-size: large; background: #8080FF; color: white; text-align: left; padding-left: 20; } +pre { font-family: courier, monospace; font-size: medium; } +a:link { color: #008000; } +a:visited { color: #008000; } +a:active { color: #FF00FF; } +a:hover { background-color: #80FF80; color: black; } +.apihdr { background: #E0E0FF; color: black; text-align: left; padding: 5; } +.indent { font-family: arial, helvetica, sans-serif; text-align: left; margin-left: 50; margin-right: 50; } + -- cgit v1.2.3