gaborator_sys/lib.rs
1//! Gaborator is a C++ library for converting audio samples to a special spectral representation
2//! that uses different FTT sizes based on whether it is bass or treble (oversimplifying here).
3//! The transformation is reversible.
4//! See [the website](https://www.gaborator.com/) for more info.
5//!
6//! This crate is a [cxx](https://cxx.rs/)-based wrapper of this library, allowing Rust code to use Gaborator (although with reduced efficiency).
7//!
8//! Limitations:
9//!
10//! * `f32` only
11//! * Not performance-minded
12//! * Some overridable or low-level details not exposed
13//! * No visualisation
14//! * Crate soundness may be iffy - I was just followed the path of least resistance.
15//! * Arithmentic overflows in buffer length calculations are not checked.
16//! * Not really tested, apart from included examples. For example, streaming should be supported, but I haven't tried it myself.
17//!
18//! Currently based on Gaborator version 1.6. Source code of the Gaborator is included into the crate.
19//!
20//! Availble examples:
21//!
22//! * Phase information randomizer, creating sort-of-reverberation audio effect.
23//! * Converts the analyzed sound to (sample,band,magnitude,phase) CSV file and back.
24//!
25//! License of Gaborator is Affero GPL 3.0.
26//!
27//! Glue code (sans doccomments copied from Gaborator) in this crate may be considered
28//! to be licensed as either MIT or AGPL-3.0, at your option.
29
30#![deny(missing_docs)]
31
32pub extern crate cxx;
33
34#[cxx::bridge(namespace = "gabbridge")]
35mod ffi {
36 /// Corresponds to `gaborator::parameters`.
37 pub struct Params {
38 /// The number of frequency bands per octave.
39 /// Values from 6 to 384 (inclusive) are supported.
40 /// Values outside this range may not work, or may cause degraded performance.
41 pub bands_per_octave: u32,
42
43 /// The lower limit of the analysis frequency range, in units of the sample rate.
44 /// The analysis filter bank will extend low enough in frequency that ff_min falls
45 /// between the two lowest frequency bandpass filters. Values from 0.001 to 0.13 are supported.
46 pub ff_min: f64,
47
48 /// The reference frequency, in units of the sample rate. This allows fine-tuning of
49 /// the analysis and synthesis filter banks such that the center frequency of one of
50 /// the filters is aligned with ff_ref. If ff_ref falls outside the frequency range of
51 /// the bandpass filter bank, this works as if the range were extended to include ff_ref.
52 /// Must be positive. A typical value when analyzing music is 440.0 / fs, where fs is the sample rate in Hz.
53 ///
54 /// Default value in C++ code is `1.0`.
55 pub ff_ref: f64,
56
57 /// A field not documented in Gaborator reference.
58 ///
59 /// Default value in C++ code is `0.7`.
60 pub overlap: f64,
61 }
62
63 /// Complex point, representing one coefficient.
64 /// Magnitude is loudness at this point, argument is phase.
65 #[derive(Copy,Clone,Debug,PartialEq,PartialOrd,Default)]
66 pub struct Coef {
67 /// Real part of the complex number
68 pub re: f32,
69 /// Imaginatry part of the complex number
70 pub im: f32,
71 }
72
73 /// Additional data for `read_coefficients_with_meta` or `write_coefficients_with_meta`
74 #[derive(Copy,Clone,Debug,PartialEq,PartialOrd,Default,Eq,Ord,Hash)]
75 pub struct CoefMeta {
76 /// The band number of the frequency band the coefficients pertain to.
77 /// This may be either a bandpass band or the lowpass band.
78 band: i32,
79
80 /// The point in time the coefficients pertain to, in samples
81 sample_time: i64,
82 }
83
84 extern "Rust" {
85 type ProcessOrFillCallback<'a>;
86
87 fn process_or_write_callback(cb: &mut ProcessOrFillCallback, meta: CoefMeta, coef: &mut Coef);
88 }
89
90 unsafe extern "C++" {
91 include!("gaborator-sys/src/gabbridge.h");
92
93 /// Represents C++'s `gaborator::analyzer<float>`. Use `new_analyzer` function to create it.
94 pub type Analyzer;
95
96 /// Reprepresents C++'s `gaborator::coefs<float>`. Create it using `create_coefs`.
97 /// Can be memory-hungry.
98 ///
99 /// (I'm not sure whether this can be dropped after `Analyzer`.
100 /// I see some mention of reference counting withing Gaborator library,
101 /// but have not checked in detail.)
102 pub type Coefs;
103
104 /// Create new instance of Gaborator analyzer/synthesizer based on supplied parameters
105 pub fn new_analyzer(params: &Params) -> UniquePtr<Analyzer>;
106
107 /// Returns the one-sided worst-case time domain support of any of the analysis filters.
108 /// When calling `analyze()` with a sample at time t, only spectrogram coefficients within
109 /// the time range t ± support will be significantly changed. Coefficients outside the range
110 /// may change, but the changes will sufficiently small that they may be ignored without significantly reducing accuracy.
111 pub fn get_analysis_support_len(b: &Analyzer) -> usize;
112
113 /// Returns the one-sided worst-case time domain support of any of the reconstruction filters.
114 /// When calling synthesize() to synthesize a sample at time t, the sample will only be significantly
115 /// affected by spectrogram coefficients in the time range t ± support. Coefficients outside the range
116 /// may be used in the synthesis, but substituting zeroes for the actual coefficient values will not significantly reduce accuracy.
117 pub fn get_synthesis_support_len(b: &Analyzer) -> usize;
118
119 /// Create `Coefs` - the holder of analyzed data.
120 pub fn create_coefs(b: &Analyzer) -> UniquePtr<Coefs>;
121
122 /// Allow the coefficients for points in time before limit
123 /// (a time in units of samples) to be forgotten.
124 /// Streaming applications can use this to free memory used by coefficients
125 /// that are no longer needed. Coefficients that have been forgotten will read as zero.
126 /// This does not guarantee that all coefficients before limit are forgotten, only that
127 /// ones for limit or later are not, and that the amount of memory consumed by
128 /// any remaining coefficients before limit is bounded.
129 pub fn forget_before(b: &Analyzer, c: Pin<&mut Coefs>, limit: i64, clean_cut: bool);
130
131
132 /// Read or write values within `Coefs`, skipping over non-existent entries.
133 /// Corresponds to `process` function of Gaborator.
134 /// `from_band` and `to_band` may be given INT_MIN / INT_MAX values, that would mean all bands.
135 /// `from_sample_time` and `to_sample_time` can also be given INT64_MIN / INT64_MAX value to mean all available data.
136 pub fn process(
137 coefs: Pin<&mut Coefs>,
138 from_band: i32,
139 to_band: i32,
140 from_sample_time: i64,
141 to_sample_time: i64,
142 callback: &mut ProcessOrFillCallback,
143 );
144
145 /// Write values to `Coefs`, creating non-existent entries as needed.
146 /// Corresponds to `fill` function of Gaborator.
147 /// `from_band` and `to_band` may be given INT_MIN / INT_MAX values, that would mean all bands.
148 /// `from_sample_time` / `to_sample_time` should not be set to overtly large range, lest memory will be exhausted.
149 pub fn fill(
150 coefs: Pin<&mut Coefs>,
151 from_band: i32,
152 to_band: i32,
153 from_sample_time: i64,
154 to_sample_time: i64,
155 callback: &mut ProcessOrFillCallback,
156 );
157
158 /// Spectrum analyze the samples at `signal` and add the resulting coefficients to `coefs`.
159 /// `t1` parameter from Gaborator's `analyze` method is caluclated based on supplied slice size.
160 ///
161 /// If the `coefs` object already contains some coefficients, the new coefficients are summed to those already present.
162 pub fn analyze(
163 b : &Analyzer,
164 signal: &[f32],
165 signal_begin_sample_number: i64,
166 coefs: Pin<&mut Coefs>,
167 );
168
169 /// Synthesize signal samples from the coefficients `coef` and store them at `signal`.
170 /// `t1` parameter from Gaborator's `synthesize` method is caluclated based on supplied slice size.
171 ///
172 /// The time range may extend outside the range analyzed using analyze(), in which case
173 /// the signal is assumed to be zero in the un-analyzed range.
174 pub fn synthesize(
175 b : &Analyzer,
176 coefs: &Coefs,
177 signal_begin_sample_number: i64,
178 signal: &mut [f32],
179 );
180
181 /// Return the smallest valid bandpass band number, corresponding to the highest-frequency bandpass filter.
182 ///
183 /// The frequency bands of the analysis filter bank are numbered by nonnegative integers that
184 /// increase towards lower (sic) frequencies. There is a number of bandpass bands corresponding
185 /// to the logarithmically spaced bandpass analysis filters, from near 0.5 (half the sample rate)
186 /// to near fmin, and a single lowpass band containing the residual signal from frequencies below fmin.
187 pub fn bandpass_bands_begin(b : &Analyzer) -> i32;
188
189 /// Return the bandpass band number one past the highest valid bandpass band number,
190 /// corresponding to one past the lowest-frequency bandpass filter.
191 pub fn bandpass_bands_end(b : &Analyzer) -> i32;
192
193 /// Return the band number of the lowpass band.
194 pub fn band_lowpass(b : &Analyzer) -> i32;
195
196 /// Return the band number corresponding to the reference frequency `ff_ref`.
197 /// 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.
198 pub fn band_ref(b : &Analyzer) -> i32;
199
200 /// Return the center frequency of band number `band`, in units of the sampling frequency.
201 pub fn band_ff(b : &Analyzer, band: i32) -> f64;
202 }
203}
204
205
206pub use ffi::*;
207/// Wrapper for your callback function for `fill` or `process`.
208///
209/// Example:
210///
211/// ```no_build
212/// gaborator_sys::process(coefs.pin_mut(), -100000, 100000, -100000, 100000, &mut gaborator_sys::ProcessOrFillCallback(Box::new(
213/// |_meta,_coef| {
214/// // read _meta, read or write _coef
215/// }
216/// )));
217/// ```
218pub struct ProcessOrFillCallback<'a>(pub Box<dyn FnMut(CoefMeta, &mut Coef) + 'a>);
219
220fn process_or_write_callback(cb: &mut ProcessOrFillCallback, meta: CoefMeta, coef: &mut Coef) {
221 cb.0(meta, coef);
222}