From d204fe8a60e0556b0294e17c5c6948cb6cee7d91 Mon Sep 17 00:00:00 2001
From: WANG <wang@wang-OptiPlex-780.(none)>
Date: Fri, 6 Sep 2013 17:25:47 +0200
Subject: [PATCH] Refactoring of Signal class by adding a rate class.

---
 examples/sinwave/output1.wav | Bin 262184 -> 393254 bytes
 interpretor/beam.ml          |   8 ++---
 interpretor/faustio.ml       |  31 ++++++++++++--------
 interpretor/process.ml       |   5 ++--
 interpretor/signal.ml        |  55 +++++++++++++++++++++++++++++------
 interpretor/types.ml         |   9 ++++--
 6 files changed, 78 insertions(+), 30 deletions(-)

diff --git a/examples/sinwave/output1.wav b/examples/sinwave/output1.wav
index 37a80e3d2f58a26ab8ca61852cd1d13bd5909fd2..f0196969f1a7273214c4a06fcaff5639cdd4ee40 100644
GIT binary patch
delta 54
zcmZ3{Ah4`Kf<4I7%}tJhZ6doO+pqtu3=9m-3z)YrU}o(4vpGSkh`CjZX{#3VzyB~A
E0NvXYPXGV_

delta 46
zcmZ41AhDuBfIZ05%}s%UWg@#G+n@i;3=9m-3z)YrU}o(4vpGSkh`CjZX{#3VzyAPJ
CZV$fz

diff --git a/interpretor/beam.ml b/interpretor/beam.ml
index b66ac2b..6e56170 100644
--- a/interpretor/beam.ml
+++ b/interpretor/beam.ml
@@ -96,12 +96,12 @@ class beam : signal_type array -> beam_type =
 		    transpose (Array.sub container 0 !index)
 		| _ -> raise x
 
-      method frequency : int array = 
-	let each_rate : signal -> int = 
+      method frequency : rate_type array = 
+	let each_rate : signal -> rate = 
 	  fun (s : signal) -> 
 	    let rate = s#frequency in
-	    if rate > 0 then rate
-	    else if rate = 0 then 44100
+	    if rate#num > 0 then rate
+	    else if rate#num = 0 then new rate 44100 1
 	    else raise (Beam_matching "frequency error.") in	
 	Array.map each_rate self#get 
 
diff --git a/interpretor/faustio.ml b/interpretor/faustio.ml
index 3094ce9..8518b5b 100644
--- a/interpretor/faustio.ml
+++ b/interpretor/faustio.ml
@@ -24,7 +24,7 @@ class virtual io =
 	  _basename <- basename; _dir <- dir
 
     method virtual read : string array -> beam
-    method virtual write : int array -> float array array array -> string array
+    method virtual write : rate array -> float array array array -> string array
     
     method private concat : float array array array -> float array array = 
       fun (origin : float array array array) ->
@@ -51,7 +51,12 @@ class waveio : io_type =
 	    let files = Array.map Sndfile.openfile paths in
 	    let frames = Array.map Int64.to_int 
 		(Array.map Sndfile.frames files) in
-	    let rates = Array.map Sndfile.samplerate files in
+	    let make_rate = 
+	      fun (denom : int) ->
+		fun (num : int) ->
+		  new rate num denom in
+	    let nums = Array.map Sndfile.samplerate files in
+	    let rates = Array.map (make_rate 1) nums in
 	    let create_container = fun l -> Array.create l 1. in
 	    let containers = Array.map create_container frames in
 	    let _ = array_map2 Sndfile.read files containers in
@@ -61,20 +66,22 @@ class waveio : io_type =
 	    array_map2 (new signal) rates (Array.map stream2func containers) in
 	  new beam signals
 
-    method write : int array -> float array array array -> string array = 
-      fun (rates : int array) ->
+    method write : rate array -> float array array array -> string array = 
+      fun (rates : rate array) ->
 	fun (output : float array array array) ->
 	  let n = Array.length output in	  
 	  let paths = Array.init n (fun i -> 
 	    _dir ^ _basename ^ (string_of_int (i + 1)) ^ ".wav") in
+	  let get_freq = fun (r : rate) -> r#to_int in
+	  let freqs = Array.map get_freq rates in
 
 	  let files = 
 	    let channels = self#channels output in 
 	    let file_format = Sndfile.format 
 		Sndfile.MAJOR_WAV Sndfile.MINOR_PCM_16 in
-	    let openwr = fun path -> fun channel -> fun rate ->
-	      Sndfile.openfile ~info:(Sndfile.RDWR, file_format, channel, rate) path in
-	    array_map3 openwr paths channels rates in 
+	    let openwr = fun path -> fun channel -> fun freq ->
+	      Sndfile.openfile ~info:(Sndfile.RDWR, file_format, channel, freq) path in
+	    array_map3 openwr paths channels freqs in 
 
 	    let data = self#concat output in
 	    let _ = array_map2 Sndfile.write files data in
@@ -106,7 +113,7 @@ class csvio : io_type =
 	let values = 
 	  let convertor = new value Zero in
 	  Array.map (convertor#of_float_array) data in
-	new signal 0 (Array.get values)
+	new signal (new rate 0 1) (Array.get values)
 
     method read : string array -> beam =
       fun (paths : string array) ->
@@ -114,8 +121,8 @@ class csvio : io_type =
 	let signals = Array.map self#csvread files in
 	new beam signals
 
-    method write : int array -> float array array array -> string array = 
-      fun (rates : int array) ->
+    method write : rate array -> float array array array -> string array = 
+      fun (rates : rate array) ->
 	fun (data : float array array array) ->
 	  let paths = 
 	    let n = Array.length data in
@@ -178,8 +185,8 @@ class iomanager =
 	    wave#set _dir _basename;
 	    csv#set _dir _basename
 
-    method write : int array -> float array array array -> string array = 
-      fun (rates : int array) ->
+    method write : rate array -> float array array array -> string array = 
+      fun (rates : rate array) ->
 	fun (data : float array array array) ->
 	  if _format = "" then
 	    raise (Invalid_argument "output format unset.")
diff --git a/interpretor/process.ml b/interpretor/process.ml
index e7568df..f094b7b 100644
--- a/interpretor/process.ml
+++ b/interpretor/process.ml
@@ -89,7 +89,8 @@ class proc_const : faust_exp -> process_type =
       method eval : beam_type -> beam_type = 
 	fun (input : beam_type) ->
 	  if input#get = [||] then
-	    new beam [| new signal 0 (fun t -> new value self#const)|]
+	    new beam [| new signal (new rate 0 1) 
+			 (fun t -> new value self#const)|]
 	  else
 	    raise (Process_error "proc_const accepts no input.")
       end;;
@@ -265,7 +266,7 @@ and proc_rec : faust_exp -> process_type =
       method eval : beam_type -> beam_type = 
 	fun (input : beam_type) ->
 	  let memory = Hashtbl.create self#delay in
-	  let rates = ref (Array.make self#dim#output 0) in
+	  let rates = ref (Array.make self#dim#output (new rate 0 1)) in
 
 	  let split : (time -> value_type array) -> (time -> value_type) array = 
 	    fun beam_at ->
diff --git a/interpretor/signal.ml b/interpretor/signal.ml
index a32923e..00a1709 100644
--- a/interpretor/signal.ml
+++ b/interpretor/signal.ml
@@ -13,8 +13,45 @@ exception Signal_operation of string;;
 
 let delay_memory_length = 10000;;
 
-class signal : int -> (time -> value_type) -> signal_type = 
-  fun (freq_init : int) ->
+class rate : int -> int -> rate_type = 
+  fun (num_init : int) ->
+    fun (denom_init : int) ->
+      let rec pgcd : int -> int -> int = 
+	fun i1 -> fun i2 ->
+	  let r = i1 mod i2 in 
+	  if r = 0 then i2 else pgcd i2 r in
+      let num_positive = 
+	if num_init >= 0 then num_init 
+	else (-num_init) in
+      let denom_positive = 
+	if denom_init > 0 then denom_init 
+	else if denom_init < 0 then -denom_init
+	else raise (Signal_operation "sample rate denominater = 0.") in
+      let factor = pgcd num_positive denom_positive in
+      let num_corrected = num_init / factor in
+      let denom_corrected = denom_init / factor in
+      object (self)
+	val _num = num_corrected
+	val _denom = denom_corrected
+	method num = _num
+	method denom = _denom
+	method to_int = 
+	  self#num / self#denom
+	method to_float = 
+	  (float_of_int self#num) /. (float_of_int self#denom)
+	method to_string = 
+	  (string_of_int self#num) ^ "/" ^ (string_of_int self#denom)
+	method equal : rate_type -> bool = 
+	  fun (r : rate_type) -> (self#num = r#num) && (self#denom = r#denom)
+	method mul : int -> rate_type = 
+	  fun (i : int) -> new rate (self#num * i) self#denom
+	method div : int -> rate_type = 
+	  fun (i : int) -> new rate self#num (self#denom * i)
+      end
+	  
+
+class signal : rate_type -> (time -> value_type) -> signal_type = 
+  fun (freq_init : rate_type) ->
     fun (func_init : time -> value_type) ->
       object (self)
 	val mutable signal_func = func_init
@@ -22,13 +59,13 @@ class signal : int -> (time -> value_type) -> signal_type =
 	method frequency = freq_init
 	method at = signal_func
 
-	method private check_freq : signal_type list -> int = 
+	method private check_freq : signal_type list -> rate_type = 
 	  fun (sl : signal_type list) ->
-	    let check : int -> signal_type -> int = 
-	      fun (f : int) ->
+	    let check : rate_type -> signal_type -> rate_type = 
+	      fun (f : rate_type) ->
 		fun (s : signal_type) ->
-		  if f = s#frequency || s#frequency = 0 then f
-		  else if f = 0 then s#frequency
+		  if f#equal s#frequency || s#frequency#num = 0 then f
+		  else if f#num = 0 then s#frequency
 		  else raise (Signal_operation "frequency not matched.") in
 	    List.fold_left check self#frequency sl
 
@@ -158,7 +195,7 @@ class signal : int -> (time -> value_type) -> signal_type =
 	    if size <= 0 then      
 	      raise (Signal_operation "Vectorize: size <= 0.")
 	    else 
-	      let freq = self#frequency / size in
+	      let freq = self#frequency#div size in
 	      let func : time -> value_type = 
 		fun t ->
 		  let vec = fun i -> (self#at (size * t + i))#get in
@@ -171,7 +208,7 @@ class signal : int -> (time -> value_type) -> signal_type =
 	    match (self#at 0)#get with
 	    | Vec vec -> vec#size
 	    | _ -> raise (Signal_operation "Serialize: scalar input.") in
-	  let freq = self#frequency * size in
+	  let freq = self#frequency#mul size in
 	  let func : time -> value_type = 
 	    fun t -> 
 	      match (self#at (t/size))#get with
diff --git a/interpretor/types.ml b/interpretor/types.ml
index f8aeeb8..620cde5 100644
--- a/interpretor/types.ml
+++ b/interpretor/types.ml
@@ -91,6 +91,9 @@ class type rate_type =
   object
     method to_int : int
     method to_float : float 
+    method to_string : string
+    method num : int
+    method denom : int
     method equal : rate_type -> bool
     method mul : int -> rate_type
     method div : int -> rate_type
@@ -98,7 +101,7 @@ class type rate_type =
 
 class type signal_type = 
     object
-      method frequency : int
+      method frequency : rate_type
       method at : time -> value_type
       method add_memory : int -> unit
       method add : signal_type -> signal_type
@@ -141,7 +144,7 @@ class type beam_type =
       method matching : int -> beam_type
       method at : time -> value_type array
       method output : int -> float array array array
-      method frequency : int array
+      method frequency : rate_type array
     end;;
 
 
@@ -170,5 +173,5 @@ class type io_type =
     object
       method set : string -> string -> unit
       method read : string array -> beam_type
-      method write : int array -> float array array array -> string array
+      method write : rate_type array -> float array array array -> string array
     end;;
-- 
2.20.1