463 lines
16 KiB
HTML
463 lines
16 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
Copyright (C) 2018-2021 Andreas Gustafsson. This file is part of
|
|
the Gaborator library source distribution. See the file LICENSE at
|
|
the top level of the distribution for license information.
|
|
-->
|
|
<html>
|
|
<head>
|
|
<link rel="stylesheet" href="../doc.css" type="text/css" />
|
|
<title>Gaborator reference: gaborator.h</title>
|
|
</head>
|
|
<body>
|
|
<h1>Gaborator reference: <code>gaborator.h</code></h1>
|
|
|
|
<h2>Spectrum Analysis Parameters</h2>
|
|
|
|
<p>A <code>parameters</code> object holds a set of parameters that
|
|
determine the frequency range and resolution of the spectrum
|
|
analysis.</p>
|
|
|
|
<pre>
|
|
class parameters {
|
|
</pre>
|
|
|
|
<div class="class_def">
|
|
<h3>Constructor</h3>
|
|
<pre>
|
|
parameters(unsigned int bands_per_octave,
|
|
double ff_min,
|
|
double ff_ref = 1.0);
|
|
</pre>
|
|
<dl>
|
|
<dt><code>bands_per_octave</code></dt>
|
|
<dd>The number of frequency bands per octave.
|
|
Values from 4 to 384 (inclusive) are supported.
|
|
</dd>
|
|
<dt><code>ff_min</code></dt>
|
|
<dd>The lower limit of the analysis frequency range, in units of the
|
|
sample rate. The analysis filter bank will extend low enough in
|
|
frequency that <code>ff_min</code> falls between the two lowest
|
|
frequency bandpass filters.
|
|
Values from 0.001 to 0.13 are supported.</dd>
|
|
<dt><code>ff_ref</code></dt>
|
|
<dd>The reference frequency, in units of the sample rate.
|
|
This allows fine-tuning of the analysis and synthesis filter
|
|
banks such that the center frequency of one of the filters
|
|
is aligned with <code>ff_ref</code>. If <code>ff_ref</code>
|
|
falls outside the frequency range of the bandpass filter bank, this
|
|
works as if the range were extended to include
|
|
<code>ff_ref</code>. Must be positive. A typical value
|
|
when analyzing music is <code>440.0 / fs</code>, where
|
|
<code>fs</code> is the sample rate in Hz.
|
|
</dd>
|
|
</dl>
|
|
<h3>Comparison</h3>
|
|
<p>
|
|
Comparison operators are provided for compatibility with
|
|
standard container classes. The ordering is arbitrary but consistent.
|
|
</p>
|
|
<pre>
|
|
bool operator<(const parameters &rhs) const;
|
|
bool operator==(const parameters &rhs) const;
|
|
</pre>
|
|
|
|
</div>
|
|
<pre>
|
|
};
|
|
</pre>
|
|
|
|
<h2>Spectrogram Coefficients</h2>
|
|
|
|
<pre class="forward_decl">
|
|
template<class T> class analyzer;
|
|
</pre>
|
|
|
|
<p>
|
|
A <code>coefs</code> object stores a set of spectrogram coefficients.
|
|
It is a dynamic data structure and will be automatically grown to
|
|
accommodate new time ranges, for example as newly recorded audio is analyzed.
|
|
The template argument <code>T</code>
|
|
must match that of the <code>analyzer</code> (usually <code>float</code>).
|
|
The template argument <code>C</code> is the data type used to store each
|
|
coefficient value; there is usually no need to specify it explicitly as
|
|
it will default to <code>std::complex<T></code>.
|
|
</p>
|
|
|
|
<pre>
|
|
template<class T, class C = std::complex<T>>
|
|
class coefs {
|
|
</pre>
|
|
<div class="class_def">
|
|
<h3>Constructor</h3>
|
|
<pre>
|
|
coefs(analyzer<T> &a);
|
|
</pre>
|
|
<p>
|
|
Construct an empty set of coefficients for use with the spectrum
|
|
analyzer <code>a</code>. This represents a signal that is zero
|
|
at all points in time.
|
|
</p>
|
|
|
|
</div>
|
|
<pre>
|
|
};
|
|
</pre>
|
|
|
|
<h2>Spectrum Analyzer</h2>
|
|
|
|
<p>
|
|
The <code>analyzer</code> object performs spectrum analysis and/or resynthesis
|
|
according to the given parameters. The template argument <code>T</code> is
|
|
the floating-point type to use for the calculations. This is typically <code>float</code>;
|
|
alternatively, <code>double</code> can be used for increased accuracy at the
|
|
expense of speed and memory consumption.</p>
|
|
|
|
<pre>template<class T>
|
|
class analyzer {</pre>
|
|
<div class="class_def">
|
|
|
|
<h3>Constructor</h3>
|
|
|
|
<pre>
|
|
analyzer(const parameters &params);
|
|
</pre>
|
|
<dl>
|
|
<dt><code>params</code></dt>
|
|
<dd>The spectrum analysis parameters.
|
|
</dl>
|
|
|
|
<h3>Analysis and synthesis</h3>
|
|
|
|
<pre>
|
|
void
|
|
analyze(const T *signal,
|
|
int64_t t0,
|
|
int64_t t1,
|
|
coefs<T> &coefs) const;
|
|
</pre>
|
|
<p>Spectrum analyze the samples at <code>*signal</code> and add the
|
|
resulting coefficients to <code>coefs</code>.
|
|
<dl>
|
|
<dt><code>signal</code></dt>
|
|
<dd>The signal samples to analyze, beginning with the sample from time <code>t0</code>
|
|
and ending with the last sample before time <code>t1</code>, for a total of
|
|
<code>t1 - t0</code> samples.
|
|
<dt><code>t0</code></dt>
|
|
<dd>The point in time when the sample at <code>signal[0]</code> was taken,
|
|
in samples. For example, when analyzing an audio recording, this is typically
|
|
0 for the first sample in the recording, but this reference point is arbitrary,
|
|
and negative times are valid. Accuracy begins to successively decrease
|
|
outside the range of about ±10<sup>8</sup> samples, so using
|
|
large time values should be avoided when they are not necessary because
|
|
of the length of the track.
|
|
</dd>
|
|
<dt><code>t1</code></dt>
|
|
<dd>The point in time of the sample one past the
|
|
end of the array of samples at <code>signal</code>,
|
|
in samples.
|
|
</dd>
|
|
<dt><code>coefs</code></dt><dd>The coefficient object that the results of the
|
|
spectrum analysis are added to.
|
|
</dl>
|
|
<p>If the <code>coefs</code> object already contains some
|
|
coefficients, the new coefficients are summed to those already
|
|
present. Because the analysis is a linear operation, this allows a
|
|
signal to be analyzed in blocks, by making multiple calls
|
|
to <code>analyze()</code> with non-overlapping ranges that together
|
|
cover the entire signal. For efficiency, the blocks should
|
|
be large, as in
|
|
<code>analyze(first_131072_samples, 0, 131072, coefs)</code>,
|
|
<code>analyze(next_131072_samples, 131072, 262144, coefs)</code>,
|
|
etc.
|
|
</p>
|
|
|
|
<pre>
|
|
void
|
|
synthesize(const coefs<T> &coefs,
|
|
uint64_t t0,
|
|
uint64_t t1,
|
|
T *signal) const;
|
|
</pre>
|
|
<p>Synthesize signal samples from the coefficients <code>coef</code> and store
|
|
them at <code>*signal</code>.
|
|
</p>
|
|
<dl>
|
|
<dt><code>coefs</code></dt><dd>The coefficients to synthesize the signal from.</dd>
|
|
<dt><code>t0</code></dt>
|
|
<dd>The point in time of the first sample to synthesize,
|
|
in samples, using the same time scale as in <code>analyze()</code>.</dd>
|
|
<dt><code>t1</code></dt>
|
|
<dd>The point in time of the sample one past the last one to synthesize.</dd>
|
|
<dt><code>signal</code></dt>
|
|
<dd>The synthesized signal samples will be written here,
|
|
beginning with the sample from time <code>t0</code> and
|
|
and ending with the last sample before time <code>t1</code>,
|
|
for a total of <code>t1 - t0</code> samples.</dd>
|
|
</dl>
|
|
<p>The time range <code>t0</code>...<code>t1</code> may extend outside
|
|
the range analyzed using <code>analyze()</code>, in which case the
|
|
signal is assumed to be zero in the un-analyzed range.</p>
|
|
|
|
<p>A signal may be synthesized in blocks by making multiple calls to
|
|
<code>analyze()</code> with different sample ranges. For efficiency,
|
|
the blocks should be large, and each <code>t0</code> should
|
|
be multiple of a large power of two.<p>
|
|
|
|
<h3>Frequency Band Numbering</h3>
|
|
|
|
<p>The frequency bands of the analysis filter bank are numbered by
|
|
nonnegative integers that increase towards lower (sic) frequencies.
|
|
There is a number of <i>bandpass bands</i> corresponding to the
|
|
logarithmically spaced bandpass analysis filters, from near 0.5
|
|
(half the sample rate) to
|
|
near f<sub>min</sub>, and a single <i>lowpass band</i> containing the
|
|
residual signal from frequencies below f<sub>min</sub>.
|
|
The numbering can be examined using the following methods:
|
|
</p>
|
|
|
|
<pre>
|
|
int bandpass_bands_begin() const;
|
|
</pre>
|
|
<p>
|
|
Return the smallest valid bandpass band number, corresponding to the
|
|
highest-frequency bandpass filter.</p>
|
|
<pre>
|
|
int bandpass_bands_end() const;
|
|
</pre>
|
|
<p>
|
|
Return the bandpass band number one past the highest valid bandpass
|
|
band number, corresponding to one past the lowest-frequency bandpass
|
|
filter.
|
|
</p>
|
|
<pre>
|
|
int band_lowpass() const;
|
|
</pre>
|
|
<p>
|
|
Return the band number of the lowpass band.
|
|
</p>
|
|
<pre>
|
|
int band_ref() const;
|
|
</pre>
|
|
<p>
|
|
Return the band number corresponding to the reference frequency
|
|
<code>ff_ref</code>. If <code>ff_ref</code> falls within
|
|
the frequency range of the bandpass filter bank, this will
|
|
be a valid bandpass band number, otherwise it will not.
|
|
</p>
|
|
<pre>
|
|
double band_ff(int band) const;
|
|
</pre>
|
|
<p>
|
|
Return the center frequency of band number <i>band</i>, in units of the
|
|
sampling frequency.
|
|
</p>
|
|
|
|
<h3>Support</h3>
|
|
<pre>
|
|
double analysis_support() const;
|
|
</pre>
|
|
<p>Returns the one-sided worst-case time domain <i>support</i> of any of the
|
|
analysis filters. When calling <code>analyze()</code> with a sample at time <i>t</i>,
|
|
only spectrogram coefficients within the time range <i>t ± support</i>
|
|
will be significantly changed. Coefficients outside the range may change,
|
|
but the changes will sufficiently small that they may be ignored without
|
|
significantly reducing accuracy.</p>
|
|
|
|
<pre>
|
|
double synthesis_support() const;
|
|
</pre>
|
|
<p>Returns the one-sided worst-case time domain <i>support</i> of any of the
|
|
reconstruction filters. When calling <code>synthesize()</code> to
|
|
synthesize a sample at time <i>t</i>, the sample will only be
|
|
significantly affected by spectrogram coefficients in the time
|
|
range <i>t ± support</i>. Coefficients outside the range may
|
|
be used in the synthesis, but substituting zeroes for the actual
|
|
coefficient values will not significantly reduce accuracy.</p>
|
|
|
|
</div>
|
|
<pre>
|
|
};
|
|
</pre>
|
|
|
|
<h2>Functions</h2>
|
|
|
|
<h3>Iterating Over Existing Coefficients</h3>
|
|
|
|
<pre>
|
|
template <class T, class F, class C0, class... CI>
|
|
void process(F f,
|
|
int b0,
|
|
int b1,
|
|
int64_t t0,
|
|
int64_t t1,
|
|
coefs<T, C0> &coefs0,
|
|
coefs<T, CI>&... coefsi);
|
|
</pre>
|
|
|
|
<p>
|
|
Process one or more coefficient sets <code>coefs0</code>... by applying
|
|
the function <code>f</code> to each coefficient present in <code>coefs0</code>,
|
|
in an indeterminate order.</p>
|
|
</p>
|
|
<p>This can be optionally limited to coefficients whose
|
|
band number <i>b</i> and sample time <i>t</i> satisfy
|
|
<code>b0</code> ≤ <i>b</i> < <code>b1</code> and
|
|
<code>t0</code> ≤ <i>t</i> < <code>t1</code>.
|
|
To process every coefficient present
|
|
in <code>coefs0</code>, pass <code>INT_MIN, INT_MAX, INT64_MIN, INT64_MAX</code>
|
|
for the arguments <code>b0</code>, <code>b1</code>, <code>t0</code>,
|
|
and <code>t1</code>, respectively.
|
|
</p>
|
|
<p>The function <code>f</code> should have the call signature</p>
|
|
<dd>
|
|
<pre>
|
|
template<class T>
|
|
void f(int b, int64_t t, std::complex<T> &c0, std::complex<T> &ci...);
|
|
</pre>
|
|
<p>where</p>
|
|
<dl>
|
|
<dt><code>b</code></dt>
|
|
<dd>The band number of the frequency band the coefficients
|
|
<code>c0</code> and <code>ci...</code> pertain to.
|
|
This may be either a bandpass band or the lowpass band.</dd>
|
|
<dt><code>t</code></dt>
|
|
<dd>The point in time the coefficients <code>c0</code> and
|
|
<code>ci...</code> pertain to, in samples</dd>
|
|
<dt><code>c0</code></dt>
|
|
<dd>A reference to a complex coefficient from <code>coefs0</code></dd>
|
|
<dt><code>ci...</code></dt>
|
|
<dd>Optional references to complex coefficients from the additional
|
|
coefficient sets <code>coefsi...</code>.</dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
|
|
<p>The function <code>f</code> may read and/or modify each of the
|
|
coefficients passed through <code>c0</code> and each
|
|
<code>ci...</code>.</p>
|
|
|
|
<p>The first coefficient set <code>c0</code> is a special case when
|
|
it comes to the treatment of missing values. Coefficients missing
|
|
from <code>c0</code> will not be iterated over at all, but when a
|
|
coefficient <i>is</i> iterated over and is missing from one of the additional
|
|
coefficient sets <code>ci...</code>, it will be automatically created
|
|
and initialized to zero in that additional coefficient set.</p>
|
|
|
|
<p><i>Note: The template parameters <code>C0</code>
|
|
and <code>CI</code>... exist to support the processing of coefficient
|
|
sets containing data of types other
|
|
than <code>std::complex<T></code>, which is not currently part of the
|
|
documented API. In typical use, there is no need to specify them when
|
|
calling <code>apply()</code> because the template parameter list
|
|
can be deduced, but if they are expicitly specified, they should all
|
|
be <code>std::complex<T></code>.
|
|
</i></p>
|
|
|
|
<h3>Creating New Coefficients</h3>
|
|
|
|
<pre>
|
|
template <class T, class F, class C0, class... CI>
|
|
void fill(F f,
|
|
int b0,
|
|
int b1,
|
|
int64_t t0,
|
|
int64_t t1,
|
|
coefs<T, C0> &coefs0,
|
|
coefs<T, CI>&... coefsi);
|
|
</pre>
|
|
<p>
|
|
Fill a region of the time-frequency plane with coefficients
|
|
and apply the function <code>f</code> to each.
|
|
</p>
|
|
<p>This works like <code>process()</code> except that it is not limited
|
|
to processing coefficients that already exist in <code>coefs0</code>;
|
|
instead, any missing coefficients in <code>coefs0</code> as well as
|
|
any of the <code>coefsi</code>... are created and initialized to zero
|
|
before <code>f</code> is called.</p>
|
|
|
|
<p>The <code>t0</code> and <code>t1</code> arguments must specify an
|
|
explicit, bounded time range — they must not be given as
|
|
INT64_MIN and/or INT64_MAX as that would mean creating coefficients
|
|
for an an astronomically large time range, requiring a correspondingly
|
|
astronomical amount of memory.</p>
|
|
|
|
<h3>Forgetting Coefficients</h3>
|
|
<pre>
|
|
template <class T>
|
|
void forget_before(const analyzer<T> &a,
|
|
coefs<T> &c,
|
|
int64_t limit);
|
|
</pre>
|
|
<p>Allow the coefficients for points in time before <code>limit</code>
|
|
(a time in units of samples) to be forgotten.
|
|
Streaming applications can use this to free memory used by coefficients
|
|
that are no longer needed. Coefficients that have been forgotten will
|
|
read as zero. This does not guarantee that all coefficients before
|
|
<code>limit</code> are forgotten, only that ones for
|
|
<code>limit</code> or later are not, and that the amount of memory
|
|
consumed by any remaining coefficients before <code>limit</code> is
|
|
bounded.</p>
|
|
|
|
<h3>Legacy API For Iterating Over Existing Coefficients</h3>
|
|
|
|
<p>Prior to version 1.5, the only way to iterate over
|
|
coefficients was the <code>apply()</code> function.
|
|
It is similar to <code>process()</code>, except that it
|
|
</p>
|
|
<ul>
|
|
<li>requires an additional <code>analyzer</code> argument,
|
|
<li>takes arguments in a different order,
|
|
<li>applies a function <code>f</code> taking arguments in a different order,
|
|
<li>does not support restricting the processing to a range of band numbers,
|
|
<li>only supports iterating over a single coefficient set, and
|
|
<li>provides default values for t0 and t1.
|
|
</ul>
|
|
<p>In new code, <code>process()</code> is preferred.</p>
|
|
|
|
<pre>
|
|
template <class T, class F>
|
|
void apply(const analyzer<T> &a,
|
|
coefs<T> &c,
|
|
F f,
|
|
int64_t t0 = INT64_MIN,
|
|
int64_t t1 = INT64_MAX);
|
|
</pre>
|
|
<p>
|
|
Apply the function <code>f</code> to each coefficient in the coefficient
|
|
set <code>c</code> for points in time <i>t</i> that satisfy
|
|
<code>t0</code> ≤ <i>t</i> < <code>t1</code>.
|
|
If the <code>t0</code> and <code>t1</code> arguments are omitted, <code>f</code>
|
|
is applied to every coefficient.
|
|
</p>
|
|
<dl>
|
|
<dt><code>a</code></dt>
|
|
<dd>The spectrum analyzer that produced the coefficients <code>c</code></dd>
|
|
<dt><code>c</code></dt>
|
|
<dd>A set of spectrogram coefficients</dd>
|
|
<dt><code>f</code></dt>
|
|
<dd>A function to apply to each coefficient in <code>c</code>,
|
|
with the call signature
|
|
<pre>
|
|
template<class T>
|
|
void f(std::complex<T> &coef, int band, int64_t t);
|
|
</pre>
|
|
<dl>
|
|
<dt><code>coef</code></dt>
|
|
<dd>A reference to a single complex coefficient. This may be read and/or modified.</dd>
|
|
<dt><code>band</code></dt>
|
|
<dd>The band number of the frequency band the coefficient <code>coef0</code> pertains to.
|
|
This may be either a bandpass band or the lowpass band.</dd>
|
|
<dt><code>t</code></dt>
|
|
<dd>The point in time the coefficient <code>c0</code> pertains to, in samples</dd>
|
|
<dt><code>t0</code></dt><dd>When not <code>INT64_MIN</code>, only apply <code>f</code> to the coefficients for time ≥ <code>t0</code></dd>
|
|
<dt><code>t1</code></dt><dd>When not <code>INT64_MAX</code>, only apply <code>f</code> to the coefficients for time < <code>t1</code></dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
|
|
<div class="nav"><span class="prev"><a href="intro.html">Previous: API Introduction</a></span><span class="next"><a href="render_h.html">Next: Spectrogram rendering: <code>render.h</code></a></span></div>
|
|
|
|
</body>
|
|
</html>
|