@@ -6,6 +6,8 @@ use std::sync::Arc;
66
77use num_rational:: Rational64 ;
88
9+ use crate :: supported_ratio;
10+
911use super :: { Convert , Error , Result } ;
1012
1113#[ inline]
@@ -97,10 +99,9 @@ pub struct Converter {
9799
98100impl Converter {
99101 #[ inline]
100- fn new ( step : f64 , order : u32 , quan : u32 , filter : Arc < Vec < f64 > > ) -> Self {
101- let rstep = Rational64 :: approximate_float ( step) . unwrap ( ) ;
102- let numer = * rstep. numer ( ) as usize ;
103- let denom = * rstep. denom ( ) as usize ;
102+ fn new ( step : Rational64 , order : u32 , quan : u32 , filter : Arc < Vec < f64 > > ) -> Self {
103+ let numer = * step. numer ( ) as usize ;
104+ let denom = * step. denom ( ) as usize ;
104105 let mut coefs = Vec :: with_capacity ( denom) ;
105106 for i in 0 ..denom {
106107 coefs. push ( i as f64 / denom as f64 ) ;
@@ -178,54 +179,43 @@ impl Convert for Converter {
178179 }
179180}
180181
181- use super :: { MAX_RATIO , MIN_RATIO } ;
182-
183182const MIN_ORDER : u32 = 1 ;
184183const MAX_ORDER : u32 = 2048 ;
185184const MIN_QUAN : u32 = 1 ;
186185const MAX_QUAN : u32 = 16384 ;
187- const MIN_CUTOFF : f64 = 0.01 ;
188- const MAX_CUTOFF : f64 = 1.0 ;
189186const MIN_ATTEN : f64 = 12.0 ;
190187const MAX_ATTEN : f64 = 180.0 ;
191188
192189#[ derive( Clone ) ]
193190pub struct Manager {
194- ratio : f64 ,
191+ ratio : Rational64 ,
195192 order : u32 ,
196193 quan : u32 ,
197194 latency : usize ,
198195 filter : Arc < Vec < f64 > > ,
199196}
200197
201198impl Manager {
202- /// Create a `Manager` with raw parameters, that means all of these should
203- /// be calculated in advance.
204- ///
205- /// - ratio: the conversion ratio, fs_new / fs_old, support [0.1, 100.0]
206- /// - quan: the quantify number, usually power of 2, support [1, 16384]
207- /// - order: the order of interpolation FIR filter, support [1, 2048]
208- /// - kaiser_beta: the beta parameter of kaiser window method, support [0.0, 20.0]
209- /// - cutoff: the cutoff of FIR filter, according to target sample rate, in [0.01, 1.0]
210- pub fn with_raw (
211- ratio : f64 ,
199+ fn with_raw_internal (
200+ ratio : Rational64 ,
212201 quan : u32 ,
213202 order : u32 ,
214203 kaiser_beta : f64 ,
215204 cutoff : f64 ,
216205 ) -> Result < Self > {
217- if !( MIN_RATIO ..= MAX_RATIO ) . contains ( & ratio) {
218- return Err ( Error :: InvalidRatio ) ;
206+ if !supported_ratio ( ratio) {
207+ return Err ( Error :: UnsupportedRatio ) ;
219208 }
220209 if !( MIN_QUAN ..=MAX_QUAN ) . contains ( & quan)
221210 || !( MIN_ORDER ..=MAX_ORDER ) . contains ( & order)
222211 || !( 0.0 ..=20.0 ) . contains ( & kaiser_beta)
223- || !( MIN_CUTOFF ..= MAX_CUTOFF ) . contains ( & cutoff)
212+ || !( 0.01 ..= 1.0 ) . contains ( & cutoff)
224213 {
225214 return Err ( Error :: InvalidParam ) ;
226215 }
227216 let filter = generate_filter_table ( quan, order, kaiser_beta, cutoff) ;
228- let latency = ( ratio * order as f64 * 0.5 ) . round ( ) as usize ;
217+ let fratio = * ratio. numer ( ) as f64 / * ratio. denom ( ) as f64 ;
218+ let latency = ( fratio * order as f64 * 0.5 ) . round ( ) as usize ;
229219 Ok ( Self {
230220 ratio,
231221 order,
@@ -235,18 +225,38 @@ impl Manager {
235225 } )
236226 }
237227
228+ /// Create a `Manager` with raw parameters, that means all of these should
229+ /// be calculated in advance.
230+ ///
231+ /// - ratio: the conversion ratio, fs_new / fs_old, support `[0.1, 10.0]`
232+ /// - quan: the quantify number, usually power of 2, support `[1, 16384]`
233+ /// - order: the order of interpolation FIR filter, support `[1, 2048]`
234+ /// - kaiser_beta: the beta parameter of kaiser window method, support `[0.0, 20.0]`
235+ /// - cutoff: the cutoff of FIR filter, according to target sample rate, in `[0.01, 1.0]`
236+ pub fn with_raw (
237+ ratio : f64 ,
238+ quan : u32 ,
239+ order : u32 ,
240+ kaiser_beta : f64 ,
241+ cutoff : f64 ,
242+ ) -> Result < Self > {
243+ let ratio = Rational64 :: approximate_float ( ratio) . unwrap_or_default ( ) ;
244+ Self :: with_raw_internal ( ratio, quan, order, kaiser_beta, cutoff)
245+ }
246+
238247 /// Create a `Manager` with attenuation, quantify and transition band width.
239248 ///
240249 /// That means the order will be calculated.
241250 ///
242- /// - ratio: the conversion ratio, fs_new / fs_old, support [0.1, 100 .0]
243- /// - atten: the attenuation in dB, support [12.0, 180.0]
244- /// - quan: the quantify number, usually power of 2, support [1, 16384]
245- /// - trans_width: the transition band width in [0.01, 1.0]
251+ /// - ratio: the conversion ratio, fs_new / fs_old, support ` [0.1, 10 .0]`
252+ /// - atten: the attenuation in dB, support ` [12.0, 180.0]`
253+ /// - quan: the quantify number, usually power of 2, support ` [1, 16384]`
254+ /// - trans_width: the transition band width in ` [0.01, 1.0]`
246255 #[ inline]
247256 pub fn new ( ratio : f64 , atten : f64 , quan : u32 , trans_width : f64 ) -> Result < Self > {
248- if !( MIN_RATIO ..=MAX_RATIO ) . contains ( & ratio) {
249- return Err ( Error :: InvalidRatio ) ;
257+ let ratio_i64 = Rational64 :: approximate_float ( ratio) . unwrap_or_default ( ) ;
258+ if !supported_ratio ( ratio_i64) {
259+ return Err ( Error :: UnsupportedRatio ) ;
250260 }
251261 if !( MIN_ATTEN ..=MAX_ATTEN ) . contains ( & atten)
252262 || !( MIN_QUAN ..=MAX_QUAN ) . contains ( & quan)
@@ -257,21 +267,22 @@ impl Manager {
257267 let kaiser_beta = calc_kaiser_beta ( atten) ;
258268 let order = calc_order ( ratio, atten, trans_width) ;
259269 let cutoff = ratio. min ( 1.0 ) * ( 1.0 - 0.5 * trans_width) ;
260- Self :: with_raw ( ratio , quan, order, kaiser_beta, cutoff)
270+ Self :: with_raw_internal ( ratio_i64 , quan, order, kaiser_beta, cutoff)
261271 }
262272
263273 /// Create a `Manager` with attenuation, quantify and order
264274 ///
265275 /// That means the transition band will be calculated.
266276 ///
267- /// - ratio: [0.1, 100 .0]
268- /// - atten: [12.0, 180.0]
269- /// - quan: [1, 16384]
270- /// - order: [1, 2048]
277+ /// - ratio: ` [0.1, 10 .0]`
278+ /// - atten: ` [12.0, 180.0]`
279+ /// - quan: ` [1, 16384]`
280+ /// - order: ` [1, 2048]`
271281 #[ inline]
272282 pub fn with_order ( ratio : f64 , atten : f64 , quan : u32 , order : u32 ) -> Result < Self > {
273- if !( MIN_RATIO ..=MAX_RATIO ) . contains ( & ratio) {
274- return Err ( Error :: InvalidRatio ) ;
283+ let ratio_i64 = Rational64 :: approximate_float ( ratio) . unwrap_or_default ( ) ;
284+ if !supported_ratio ( ratio_i64) {
285+ return Err ( Error :: UnsupportedRatio ) ;
275286 }
276287 if !( MIN_ATTEN ..=MAX_ATTEN ) . contains ( & atten)
277288 || !( MIN_QUAN ..=MAX_QUAN ) . contains ( & quan)
@@ -282,7 +293,7 @@ impl Manager {
282293 let kaiser_beta = calc_kaiser_beta ( atten) ;
283294 let trans_width = calc_trans_width ( ratio, atten, order) ;
284295 let cutoff = ratio. min ( 1.0 ) * ( 1.0 - 0.5 * trans_width) ;
285- Self :: with_raw ( ratio , quan, order, kaiser_beta, cutoff)
296+ Self :: with_raw_internal ( ratio_i64 , quan, order, kaiser_beta, cutoff)
286297 }
287298
288299 /// Create a `Converter` which actually implement the interpolation.
@@ -316,15 +327,12 @@ mod tests {
316327 #[ test]
317328 fn test_manager_with_raw ( ) {
318329 assert ! ( Manager :: with_raw( 2.0 , 32 , 32 , 5.0 , 0.8 ) . is_ok( ) ) ;
319- assert ! ( Manager :: with_raw( 0.01 , 32 , 32 , 5.0 , 0.8 ) . is_ok( ) ) ;
320- assert ! ( Manager :: with_raw( 100.0 , 32 , 32 , 5.0 , 0.8 ) . is_ok( ) ) ;
321- assert ! ( Manager :: with_raw( 0.009 , 32 , 32 , 5.0 , 0.8 ) . is_err( ) ) ;
322- assert ! ( Manager :: with_raw( 100.1 , 32 , 32 , 5.0 , 0.8 ) . is_err( ) ) ;
323330 assert ! ( Manager :: with_raw( 2.0 , 0 , 32 , 5.0 , 0.8 ) . is_err( ) ) ;
324331 assert ! ( Manager :: with_raw( 2.0 , 32 , 0 , 5.0 , 0.8 ) . is_err( ) ) ;
325- assert ! ( Manager :: with_raw( 2.0 , 32 , 32 , 5.0 , - 0.1 ) . is_err( ) ) ;
332+ assert ! ( Manager :: with_raw( 2.0 , 32 , 32 , 5.0 , 0.0 ) . is_err( ) ) ;
326333 assert ! ( Manager :: with_raw( 2.0 , 32 , 32 , 5.0 , 1.1 ) . is_err( ) ) ;
327334 assert ! ( Manager :: with_raw( 2.0 , 32 , 32 , -0.1 , 0.8 ) . is_err( ) ) ;
335+ assert ! ( Manager :: with_raw( 2.0 , 32 , 32 , 20.1 , 0.8 ) . is_err( ) ) ;
328336 }
329337
330338 #[ test]
0 commit comments