struct

(**

Description

La fonction

etat
effectue certains calculs suivant les données provenant du clavier.

Copyright Stéphane Grognet
IREM des Pays de la Loire - Université de Nantes
Laboratoire de mathématiques Jean Leray UMR 6629 CNRS
version 0.7
@version 0.7 @author Stéphane Grognet @since 2014, 2015 *)


(** Les deux fonctions qui suivent servent à replier le clavier quand les harmoniques sortent de l'ambitus MIDI. *)


let plus = fun (x:int) (y:int) ->
 let z = ref ( x + y ) in
  while !z > 127 do
   z := !z - 12 ;
  done ;
  while !z < 0 do
   z := !z + 12 ;
  done ;
  !z ;;

let plusplus = fun (bord_bas:int) (bord_haut:int) (x:int) (y:int) ->
 let z = ref ( x + y ) in
  while !z > bord_haut do
   z := !z - 12 ;
  done ;
  while !z < bord_bas do
   z := !z + 12 ;
  done ;
  !z ;;


let moins = fun (x:int) (y:int) ->
 let z = ref ( x - y ) in
  while !z > 127 do
   z := !z - 12 ;
  done ;
  while !z < 0 do
   z := !z + 12 ;
  done ;
  !z ;;

let rec terme_geometrique = fun (accu:float) (n:int) (x:float) ->
 match n with
 | 0 -> accu
 | 1 -> accu *. x
 | 2 -> accu *. x *. x
 | negatif when negatif < 0 -> terme_geometrique accu ( - n ) ( 1. /. x )
 | pair when pair land 1 = 0 -> terme_geometrique accu ( n / 2 ) ( x *. x )
 | _ -> terme_geometrique ( accu *. x ) ( n / 2 ) ( x *. x ) ;;

let int_pow = fun (n:int) (x:float) ->
 terme_geometrique 1. n x ;;

let gain = function (x:int) ->
 if x = 0 then
  0.
 else
  int_pow ( 127 - x ) Data.coefficient_gain ;;

let gain_reel = function (x:float) ->
 gain ( int_of_float x ) ;;

let gain_rapide = function (x:int) ->
 if x = 0 then
  0.
 else
  int_pow ( 127 - x ) Data.coefficient_rapide ;;

let gain_rapide_reel = function (x:float) ->
 gain_rapide ( int_of_float x ) ;;

let antigain = function (x:int) ->
 if x = 127 then
  0.
 else
  int_pow x Data.coefficient_tirettes ;;

let antigain_reel = function (x:float) ->
 antigain ( int_of_float x ) ;;

let antigain_rapide = function (x:int) ->
 if x = 127 then
  0.
 else
  int_pow x Data.coefficient_gain ;;

let antigain_rapide_reel = function (x:float) ->
 antigain_rapide ( int_of_float x ) ;;

let antigain_lent = function (x:int) ->
 if x = 127 then
  0.
 else
  int_pow x Data.coefficient_lent ;;

let antigain_lent_reel = function (x:float) ->
 antigain_lent ( int_of_float x ) ;;

let gain_median = 1. /. ( gain 64 ) ;;

let angle = function (x:float) ->
 Data.angle_mini *. x ;;

let rec repartition = function (x:int) ->
 match x with
 | negatif when x <= 0 -> [| 1. ; 0. |]
 | 64 -> Array.make 2 Data.pas32
 | petit when petit < 64 ->
  begin
   let y = ref 1. in
    if x land 1 > 0 then
     y := !y *. Data.pas ;
    if x land 2 > 0 then
     y := !y *. Data.pas2 ;
    if x land 4 > 0 then
     y := !y *. Data.pas4 ;
    if x land 8 > 0 then
     y := !y *. Data.pas8 ;
    if x land 16 > 0 then
     y := !y *. Data.pas16 ;
    if x land 32 > 0 then
     y := !y *. Data.pas32 ;
    let z = 1. -. !y in
     let w = 1. /. ( sqrt ( max !y z ) ) in
      [| w *. !y ; w *. z |] ;
  end
 | grand when grand >= 127 -> [| 0. ; 1. |]
 | _ -> 
    (** 65 <= x <= 126 *)

  begin
   let a = repartition ( 127 - x ) in
    [| a.(1) ; a.(0) |] ;
  end ;;

let trirepartition = function (x:int) ->
 match x with
 | petit when petit < 64 ->
  begin
   let a = repartition ( 2 * x ) in
    [| a.(0) ; a.(1) ; 0. |] ;
  end
 | grand when grand > 64 ->
  begin
   let a = repartition ( 2 * ( x - 64 ) ) in
    [| 0. ; a.(0) ; a.(1) |] ;
  end
 | _ -> [| 0. ; 1. ; 0. |] ;; 
            (** x = 64 *)



let etat = fun (forme:float array) (notes:int array) (ages:int array array) (sons:float array array) (enveloppes:float array array) (parametres:float array) ->
 for i = 0 to 127 do
  let ligne = sons.(i)
  and row = enveloppes.(i) in
   for j = 0 to 8 do
    ligne.(j) <- 0. ;
    row.(j) <- 0. ;
   done ;
 done ;
 let tirettes = Array.make 9 0.
 and ic = open_in_gen [Open_binary ; Open_rdonly] 0o400 Data.adresse_etat_clavier in
  for i = 0 to 127 do
   notes.(i) <- input_byte ic ;
  done ;
  for i = 0 to pred Data.nombre_de_parametres_clavier do
   parametres.(i) <- float ( input_byte ic ) ;
  done ;
  close_in_noerr ic ;
(** On part du principe que la commande 0 est le pitch, que les commandes 1 à 18 sont les tirettes, que les commandes 19 à 50 sont des boutons rotatifs, que les commandes 51 à 53 sont des boutons-poussoirs. Sur le pitch bend, la valeur centrale de repos est à 64. Sur les tirettes, la valeur maximale est à 0, la minimale à 127. Sur les boutons rotatifs la valeur maximale est à 127 et la minimale à 0. Le bouton du diapason a une valeur par défaut de 64 au démarrage. *)

  let k = ( int_of_float parametres.(Data.molette_pitch) ) - 64 in
   let pitch = int_pow k Data.excursion_pitch in
    parametres.(Data.molette_pitch) <- pitch ;
    parametres.(Data.bouton_diapason) <- 441. *. Data.coefficient_diapason ** ( parametres.(Data.bouton_diapason) -. 64. ) ;
    parametres.(Data.bouton_octave) <- 2. +. Data.coefficient_octave *. parametres.(Data.bouton_octave) ;
    let diapason = parametres.(Data.bouton_diapason) *. pitch in
     Data.pulsation diapason parametres.(Data.bouton_octave) parametres.(Data.bouton_rose) Data.adresse_rotation ;

(** tirettes *)


    for i = 1 to 9 do
     parametres.(i) <- antigain_reel parametres.(i) ;
    done ;
    for i = 10 to 18 do
     parametres.(i) <- antigain_reel ( min 126. parametres.(i) ) ;
     tirettes.( i - 10 ) <- parametres.(i) ;
    done ;

(** boutons rotatifs *)


    parametres.(Data.bouton_saturation) <- gain_reel parametres.(Data.bouton_saturation) ;
    parametres.(Data.bouton_dephasage_inflexion) <- angle parametres.(Data.bouton_dephasage_inflexion) ;
    parametres.(Data.bouton_dephasage_creneaux) <- angle parametres.(Data.bouton_dephasage_creneaux) ;
    parametres.(Data.bouton_longueur_clic) <- ( gain_reel parametres.(Data.bouton_longueur_clic) ) *. Data.pred_taille_d_echantillon_reelle ;
    parametres.(Data.bouton_niveau_clic) <- gain_reel parametres.(Data.bouton_niveau_clic) ;
    parametres.(Data.bouton_coupure) <- float ( ( 127 - ( int_of_float parametres.(Data.bouton_coupure) ) ) / 3 ) ;
    parametres.(Data.bouton_delai_reverb) <- parametres.(Data.bouton_delai_reverb) *. Data.coeff_delai ;
    parametres.(Data.bouton_niveau_reverb) <- gain_reel parametres.(Data.bouton_niveau_reverb) ;
    parametres.(Data.bouton_traine) <- Data.coeff_traine *. ( gain_rapide_reel ( max 1. parametres.(Data.bouton_traine) ) ) ;
    parametres.(Data.bouton_nervosite) <- 1e6 *. ( gain_rapide_reel ( max 1. parametres.(Data.bouton_nervosite) ) ) ;
    parametres.(Data.bouton_remanence) <- gain_reel parametres.(Data.bouton_remanence) ;
    parametres.(Data.bouton_pente_remanence) <- antigain_lent_reel parametres.(Data.bouton_pente_remanence) ;

(** notes *)


    let bord_bas = max 0 ( min 63 ( int_of_float parametres.(Data.bouton_pli_bas) ) )
    and bord_haut = max 64 ( min 127 ( int_of_float parametres.(Data.bouton_pli_haut) ) )
    and nervosite = parametres.(Data.bouton_nervosite)
    and remanence = parametres.(Data.bouton_remanence)
    and pente_remanence = parametres.(Data.bouton_pente_remanence)
    and traine = parametres.(Data.bouton_traine) in
     let decalage = Data.max_de_forme *. ( 1. -. 1. /. nervosite )
     and a = ref 0
     and alpha = Data.inv_16129 *. ( 127. -. parametres.(Data.bouton_swell) )
     and beta = Data.inv_127 *. parametres.(Data.bouton_swell) in
      for i = 0 to 127 do
       let velocite = notes.(i) in
        if velocite > 0 then
         begin
          let n = alpha *. float velocite +. beta
          and rappuie = ( velocite >= 128 ) in
           if rappuie then
            begin
             let valeur = 255 - notes.(i) in
              Clavier.aux Data.adresse_etat_clavier i valeur ;
              notes.(i) <- valeur ;
            end ;
           for k = 0 to 8 do
            let index = plusplus bord_bas bord_haut i Data.tirettes.(k) in
             if rappuie then
              a := 0
             else
              a := ages.(index).(k) ;
             sons.(index).(k) <- sons.(index).(k) +. parametres.( 1 + k ) *. n ;
             enveloppes.(index).(k) <- enveloppes.(index).(k) +. Data.enveloppe forme decalage nervosite ( remanence *. int_pow !a pente_remanence ) ( traine *. tirettes.(k) *. float !a ) ;
             ages.(index).(k) <- succ !a ;
           done ;
         end
        else
         begin
          for k = 0 to 8 do
           let index = plusplus bord_bas bord_haut i Data.tirettes.(k) in
            ages.(index).(k) <- 0 ;
          done ;
         end
      done ;;


end