ccd1a8d5a212 — Chris Cannam 3 years ago
Support resampler branch of bqresample api
M bqresample.sig +9 -3
@@ 8,10 8,16 @@ signature BQ_RESAMPLE = sig
     type ratio
 
     datatype quality = BEST | FASTEST_TOLERABLE | FASTEST
+    datatype dynamism = RATIO_OFTEN_CHANGING | RATIO_MOSTLY_FIXED
+    datatype ratio_change = SMOOTH_RATIO_CHANGE | SUDDEN_RATIO_CHANGE
 		     
-    (** Create a new resampler supporting the given number of
-       channels. *)
-    val new : quality * int -> t
+    (** Create a new resampler with the given quality parameters,
+        supporting the given number of channels. *)
+    val new : { channels : int,
+                quality : quality,
+                dynamism : dynamism,
+                ratio_change : ratio_change
+              } -> t
 
     (** Obtain the number of channels of the given resampler. *)
     val channels : t -> int

          
M ffi/bqresample.sml +18 -8
@@ 13,18 13,28 @@ structure BqResample :>
     type ratio = real
 
     datatype quality = BEST | FASTEST_TOLERABLE | FASTEST
+    datatype dynamism = RATIO_OFTEN_CHANGING | RATIO_MOSTLY_FIXED
+    datatype ratio_change = SMOOTH_RATIO_CHANGE | SUDDEN_RATIO_CHANGE
                                                               
     fun new_arr n = RealArray.array (n, 0.0)
     val to_vec = _prim "Array_toVector" : RealArray.array -> RealVector.vector;
-                    
-    fun new (quality, channels) =
-        let val ffiq = case quality of
-                           BEST => 2
-                         | FASTEST_TOLERABLE => 1
-                         | FASTEST => 0
+
+    fun new { channels, quality, dynamism, ratio_change } =
+        let val ffi_quality = case quality of
+                                  BEST => 0
+                                | FASTEST_TOLERABLE => 1
+                                | FASTEST => 2
+            val ffi_dynamism = case dynamism of
+                                   RATIO_OFTEN_CHANGING => 0
+                                 | RATIO_MOSTLY_FIXED => 1
+            val ffi_ratioChange = case ratio_change of
+                                      SMOOTH_RATIO_CHANGE => 0
+                                    | SUDDEN_RATIO_CHANGE => 1
             val resampler = MLton.Finalizable.new
-                                (bq_resample_new (Int32.fromInt ffiq,
-                                                  Int32.fromInt channels))
+                                (bq_resample_new (Int32.fromInt channels,
+                                                  Int32.fromInt ffi_quality,
+                                                  Int32.fromInt ffi_dynamism,
+                                                  Int32.fromInt ffi_ratioChange))
             val _ = MLton.Finalizable.addFinalizer
                         (resampler, bq_resample_delete)
         in

          
M ffi/impl-bqresample.cpp +11 -3
@@ 37,15 37,23 @@ extern "C" {
         delete rec;
     }
     
-    Pointer bq_resample_new(Int32 quality, Int32 channels) {
+    Pointer bq_resample_new(Int32 channels, Int32 quality,
+                            Int32 dynamism, Int32 ratioChange) {
 	try {
 	    resampler_rec *rec = new_resampler_rec();
 	    size_t bufsiz = 10240;
             breakfastquay::Resampler::Parameters params;
             params.quality =
-                (quality == 0 ? breakfastquay::Resampler::Fastest :
-                 quality == 2 ? breakfastquay::Resampler::Best :
+                (quality == 0 ? breakfastquay::Resampler::Best :
+                 quality == 2 ? breakfastquay::Resampler::Fastest :
                  breakfastquay::Resampler::FastestTolerable);
+            params.dynamism =
+                (dynamism == 0 ? breakfastquay::Resampler::RatioOftenChanging :
+                 breakfastquay::Resampler::RatioMostlyFixed);
+            params.ratioChange =
+                (ratioChange == 0 ? breakfastquay::Resampler::SmoothRatioChange :
+                 breakfastquay::Resampler::SuddenRatioChange);
+            
             params.initialSampleRate = 44100; //!!!
             params.maxBufferSize = bufsiz;
 	    rec->resampler = new breakfastquay::Resampler(params, channels);

          
M ffi/import-bqresample.sml +1 -1
@@ 8,7 8,7 @@ structure ImportBqResample = struct
 
     val bq_resample_new =
         _import "bq_resample_new" private:
-        Int32.int * Int32.int -> resamplehandle;
+        Int32.int * Int32.int * Int32.int * Int32.int -> resamplehandle;
 
     val bq_resample_get_channel_count =
         _import "bq_resample_get_channel_count" private:

          
M sml/bqaudiostream.sml +7 -3
@@ 73,9 73,13 @@ functor BqAudioReadStreamFn (S: READ_STR
                             stream = #stream t,
                             read_rate = rate,
                             ratio = Real.fromInt rate / Real.fromInt (#read_rate t),
-                            resampler = SOME (BqResample.new
-						  (BqResample.FASTEST_TOLERABLE,
-						   channels t))
+                            resampler =
+                            SOME (BqResample.new
+                                      { channels = channels t,
+                                        quality = BqResample.FASTEST_TOLERABLE,
+                                        dynamism = BqResample.RATIO_MOSTLY_FIXED,
+                                        ratio_change = BqResample.SUDDEN_RATIO_CHANGE
+                                      })
                         }
           | err => err
 

          
M sml/bqresample.sml +9 -0
@@ 6,6 6,15 @@ structure BqResample
 
     open Resampler
 
+    (*!!! todo: update bsq-resampler itself with these, after bqresample *)
+    datatype dynamism = RATIO_OFTEN_CHANGING | RATIO_MOSTLY_FIXED
+    datatype ratio_change = SMOOTH_RATIO_CHANGE | SUDDEN_RATIO_CHANGE
+    fun new { channels : int,
+              quality : quality,
+              dynamism : dynamism,
+              ratio_change : ratio_change } =
+        Resampler.new (quality, channels)
+
     val set_verbosity = setVerbosity
              
     fun resample_interleaved (t, inbuf, ratio, final) =

          
M test/test-bqresample.sml +6 -1
@@ 25,7 25,12 @@ structure TestBqResample : TESTS = struc
          fn () =>
             (* Interpolating a sinusoid should give us a sinusoid,
                once we've dropped the first few samples *)
-            let val resampler = BqResample.new (BqResample.FASTEST_TOLERABLE, 1)
+            let val resampler = BqResample.new
+                                    { channels = 1,
+                                      quality = BqResample.FASTEST_TOLERABLE,
+                                      dynamism = BqResample.RATIO_MOSTLY_FIXED,
+                                      ratio_change = BqResample.SUDDEN_RATIO_CHANGE
+                                    }
                 val ratio = 2.0
                 val test_sine = sinusoid (2000, 8.0,
                                           { frequency = 2.0,