1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
//! Gaborator is a C++ library for converting audio samples to a special spectral representation //! that uses different FTT sizes based on whether it is bass or treble (oversimplifying here). //! The transformation is reversible. //! See [the website](https://www.gaborator.com/) for more info. //! //! This crate is a [cxx](https://cxx.rs/)-based wrapper of this library, allowing Rust code to use Gaborator (although with reduced efficiency). //! //! Limitations: //! //! * `f32` only //! * Not performance-minded //! * Some overridable or low-level details not exposed //! * No visualisation //! * Crate soundness may be iffy - I was just followed the path of least resistance. //! * Arithmentic overflows in buffer length calculations are not checked. //! * Not really tested, apart from included examples. For example, streaming should be supported, but I haven't tried it myself. //! //! Currently based on Gaborator version 1.6. Source code of the Gaborator is included into the crate. //! //! Availble examples: //! //! * Phase information randomizer, creating sort-of-reverberation audio effect. //! * Converts the analyzed sound to (sample,band,magnitude,phase) CSV file and back. //! //! License of Gaborator is Affero GPL 3.0. //! //! Glue code (sans doccomments copied from Gaborator) in this crate may be considered //! to be licensed as either MIT or AGPL-3.0, at your option. #![deny(missing_docs)] pub use gaborator_sys::{Coef, CoefMeta, Params as GaboratorParams}; /// Reprepresents C++'s `gaborator::coefs<float>` /// Can be memory-hungry. /// /// (I'm not sure whether this can be dropped after `Analyzer`. /// I see some mention of reference counting withing Gaborator library, /// but have not checked in detail.) pub struct Coefs(gaborator_sys::cxx::UniquePtr<gaborator_sys::Coefs>); impl Coefs { /// Create new instance of Gaborator analyzer/synthesizer based on supplied parameters pub fn new(gab: &Gaborator) -> Self { Coefs( gaborator_sys::create_coefs(&*gab.0) ) } /// 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. pub fn forget_before(&mut self, g:&Gaborator, limit: i64, clean_cut: bool) { gaborator_sys::forget_before( &*g.0, self.0.pin_mut(), limit, clean_cut, ) } /// Read or write values within `Coefs`, skipping over non-existent entries. /// Corresponds to `process` function of Gaborator. /// `from_band` and `to_band` may be given INT_MIN / INT_MAX values, that would mean all bands. /// `from_sample_time` and `to_sample_time` can also be given INT64_MIN / INT64_MAX value to mean all available data. pub fn process( &mut self, from_band: i32, to_band: i32, from_sample_time: i64, to_sample_time: i64, callback: impl FnMut(CoefMeta, &mut Coef), ) { gaborator_sys::process( self.0.pin_mut(), from_band, to_band, from_sample_time, to_sample_time, &mut gaborator_sys::ProcessOrFillCallback(Box::new(callback)), ) } /// Write values to `Coefs`, creating non-existent entries as needed. /// Corresponds to `fill` function of Gaborator. /// `from_band` and `to_band` may be given INT_MIN / INT_MAX values, that would mean all bands. /// `from_sample_time` / `to_sample_time` should not be set to overtly large range, lest memory will be exhausted. pub fn fill( &mut self, from_band: i32, to_band: i32, from_sample_time: i64, to_sample_time: i64, callback: impl FnMut(CoefMeta, &mut Coef), ) { gaborator_sys::fill( self.0.pin_mut(), from_band, to_band, from_sample_time, to_sample_time, &mut gaborator_sys::ProcessOrFillCallback(Box::new(callback)), ) } } /// Main type of the crate. Represents C++'s `gaborator::analyzer<float>`. pub struct Gaborator(gaborator_sys::cxx::UniquePtr<gaborator_sys::Analyzer>); impl Gaborator { /// Create new instance of Gaborator analyzer/synthesizer based on supplied parameters pub fn new(params: &GaboratorParams) -> Self { Gaborator( gaborator_sys::new_analyzer(params) ) } /// 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. pub fn analysis_support_len(&self) -> usize { gaborator_sys::get_analysis_support_len(&*self.0) } /// 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. pub fn synthesis_support_len(&self) -> usize { gaborator_sys::get_synthesis_support_len(&*self.0) } /// Return the smallest valid bandpass band number, corresponding to the highest-frequency bandpass filter. /// /// 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. pub fn bandpass_bands_begin(&self) -> i32 { gaborator_sys::bandpass_bands_begin(&*self.0) } /// Return the bandpass band number one past the highest valid bandpass band number, /// corresponding to one past the lowest-frequency bandpass filter. pub fn bandpass_bands_end(&self) -> i32 { gaborator_sys::bandpass_bands_end(&*self.0) } /// Return the band number of the lowpass band. pub fn band_lowpass(&self) -> i32 { gaborator_sys::band_lowpass(&*self.0) } /// 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. pub fn band_ref(&self) -> i32 { gaborator_sys::band_ref(&*self.0) } /// Return the center frequency of band number `band`, in units of the sampling frequency. pub fn band_ff(&self, band: i32) -> f64 { gaborator_sys::band_ff(&*self.0, band) } /// Spectrum analyze the samples at `signal` and add the resulting coefficients to `coefs`. /// `t1` parameter from Gaborator's `analyze` method is caluclated based on supplied slice size. /// /// If the `coefs` object already contains some coefficients, the new coefficients are summed to those already present. pub fn analyze( &self, signal: &[f32], signal_begin_sample_number: i64, coefs: &mut Coefs, ) { gaborator_sys::analyze( &*self.0, signal, signal_begin_sample_number, coefs.0.pin_mut(), ) } /// Synthesize signal samples from the coefficients `coef` and store them at `signal`. /// `t1` parameter from Gaborator's `synthesize` method is caluclated based on supplied slice size. /// /// The time range may extend outside the range analyzed using analyze(), in which case /// the signal is assumed to be zero in the un-analyzed range. pub fn synthesize( &self, coefs: &Coefs, signal_begin_sample_number: i64, signal: &mut [f32], ) { gaborator_sys::synthesize( &*self.0, &*coefs.0, signal_begin_sample_number, signal, ) } }