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}