gaborator.h
A parameters
object holds a set of parameters that
determine the frequency range and resolution of the spectrum
analysis.
class parameters {
parameters(unsigned int bands_per_octave, double ff_min, double ff_ref = 1.0);
bands_per_octave
ff_min
ff_min
falls between the two lowest
frequency bandpass filters.
Values from 0.001 to 0.13 are supported.ff_ref
ff_ref
. If ff_ref
falls outside the frequency range of the bandpass filter bank, this
works as if the range were extended to include
ff_ref
. Must be positive. A typical value
when analyzing music is 440.0 / fs
, where
fs
is the sample rate in Hz.
Comparison operators are provided for compatibility with standard container classes. The ordering is arbitrary but consistent.
bool operator
};
template<class T> class analyzer;
A coefs
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 T
must match that of the analyzer
(usually float
).
The template argument C
is the data type used to store each
coefficient value; there is usually no need to specify it explicitly as
it will default to std::complex<T>
.
template<class T, class C = std::complex<T>> class coefs {
coefs(analyzer<T> &a);
Construct an empty set of coefficients for use with the spectrum
analyzer a
. This represents a signal that is zero
at all points in time.
};
The analyzer
object performs spectrum analysis and/or resynthesis
according to the given parameters. The template argument T
is
the floating-point type to use for the calculations. This is typically float
;
alternatively, double
can be used for increased accuracy at the
expense of speed and memory consumption.
template<class T> class analyzer {
analyzer(const parameters ¶ms);
params
void analyze(const T *signal, int64_t t0, int64_t t1, coefs<T> &coefs) const;
Spectrum analyze the samples at *signal
and add the
resulting coefficients to coefs
.
signal
t0
and ending with the last sample before time t1
, for a total of
t1 - t0
samples.
t0
signal[0]
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 ±108 samples, so using
large time values should be avoided when they are not necessary because
of the length of the track.
t1
signal
,
in samples.
coefs
If the coefs
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 analyze()
with non-overlapping ranges that together
cover the entire signal. For efficiency, the blocks should
be large, as in
analyze(first_131072_samples, 0, 131072, coefs)
,
analyze(next_131072_samples, 131072, 262144, coefs)
,
etc.
void synthesize(const coefs<T> &coefs, uint64_t t0, uint64_t t1, T *signal) const;
Synthesize signal samples from the coefficients coef
and store
them at *signal
.
coefs
t0
analyze()
.t1
signal
t0
and
and ending with the last sample before time t1
,
for a total of t1 - t0
samples.The time range t0
...t1
may extend outside
the range analyzed using analyze()
, in which case the
signal is assumed to be zero in the un-analyzed range.
A signal may be synthesized in blocks by making multiple calls to
analyze()
with different sample ranges. For efficiency,
the blocks should be large, and each t0
should
be multiple of a large power of two.
The frequency bands of the analysis filter bank are numbered by nonnegative integers that increase towards lower (sic) frequencies. There is a number of bandpass bands corresponding to the logarithmically spaced bandpass analysis filters, from near 0.5 (half the sample rate) to near fmin, and a single lowpass band containing the residual signal from frequencies below fmin. The numbering can be examined using the following methods:
int bandpass_bands_begin() const;
Return the smallest valid bandpass band number, corresponding to the highest-frequency bandpass filter.
int bandpass_bands_end() const;
Return the bandpass band number one past the highest valid bandpass band number, corresponding to one past the lowest-frequency bandpass filter.
int band_lowpass() const;
Return the band number of the lowpass band.
int band_ref() const;
Return the band number corresponding to the reference frequency
ff_ref
. If ff_ref
falls within
the frequency range of the bandpass filter bank, this will
be a valid bandpass band number, otherwise it will not.
double band_ff(int band) const;
Return the center frequency of band number band, in units of the sampling frequency.
double analysis_support() const;
Returns the one-sided worst-case time domain support of any of the
analysis filters. When calling analyze()
with a sample at time t,
only spectrogram coefficients within the time range t ± support
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.
double synthesis_support() const;
Returns the one-sided worst-case time domain support of any of the
reconstruction filters. When calling synthesize()
to
synthesize a sample at time t, the sample will only be
significantly affected by spectrogram coefficients in the time
range t ± support. Coefficients outside the range may
be used in the synthesis, but substituting zeroes for the actual
coefficient values will not significantly reduce accuracy.
};
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);
Process one or more coefficient sets coefs0
... by applying
the function f
to each coefficient present in coefs0
,
in an indeterminate order.
This can be optionally limited to coefficients whose
band number b and sample time t satisfy
b0
≤ b < b1
and
t0
≤ t < t1
.
To process every coefficient present
in coefs0
, pass INT_MIN, INT_MAX, INT64_MIN, INT64_MAX
for the arguments b0
, b1
, t0
,
and t1
, respectively.
The function f
should have the call signature
template<class T> void f(int b, int64_t t, std::complex<T> &c0, std::complex<T> &ci...);
where
b
c0
and ci...
pertain to.
This may be either a bandpass band or the lowpass band.t
c0
and
ci...
pertain to, in samplesc0
coefs0
ci...
coefsi...
.The function f
may read and/or modify each of the
coefficients passed through c0
and each
ci...
.
The first coefficient set c0
is a special case when
it comes to the treatment of missing values. Coefficients missing
from c0
will not be iterated over at all, but when a
coefficient is iterated over and is missing from one of the additional
coefficient sets ci...
, it will be automatically created
and initialized to zero in that additional coefficient set.
Note: The template parameters C0
and CI
... exist to support the processing of coefficient
sets containing data of types other
than std::complex<T>
, which is not currently part of the
documented API. In typical use, there is no need to specify them when
calling apply()
because the template parameter list
can be deduced, but if they are expicitly specified, they should all
be std::complex<T>
.
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);
Fill a region of the time-frequency plane with coefficients
and apply the function f
to each.
This works like process()
except that it is not limited
to processing coefficients that already exist in coefs0
;
instead, any missing coefficients in coefs0
as well as
any of the coefsi
... are created and initialized to zero
before f
is called.
The t0
and t1
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.
template <class T> void forget_before(const analyzer<T> &a, coefs<T> &c, int64_t limit);
Allow the coefficients for points in time before limit
(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
limit
are forgotten, only that ones for
limit
or later are not, and that the amount of memory
consumed by any remaining coefficients before limit
is
bounded.
Prior to version 1.5, the only way to iterate over
coefficients was the apply()
function.
It is similar to process()
, except that it
analyzer
argument,
f
taking arguments in a different order,
In new code, process()
is preferred.
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);
Apply the function f
to each coefficient in the coefficient
set c
for points in time t that satisfy
t0
≤ t < t1
.
If the t0
and t1
arguments are omitted, f
is applied to every coefficient.
a
c
c
f
c
,
with the call signature
template<class T> void f(std::complex<T> &coef, int band, int64_t t);
coef
band
coef0
pertains to.
This may be either a bandpass band or the lowpass band.t
c0
pertains to, in samplest0
INT64_MIN
, only apply f
to the coefficients for time ≥ t0
t1
INT64_MAX
, only apply f
to the coefficients for time < t1