Changeset 7195
- Timestamp:
- 02/23/10 06:47:00 (7 months ago)
- Location:
- trunk/liquidsoap/src
- Files:
-
- 6 modified
-
clock.ml (modified) (1 diff)
-
clock.mli (modified) (2 diffs)
-
lang/lang.ml (modified) (1 diff)
-
operators/cross.ml (modified) (4 diffs)
-
source.ml (modified) (7 diffs)
-
source.mli (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/liquidsoap/src/clock.ml
r7194 r7195 63 63 64 64 val mutable outputs = [] 65 66 65 method attach s = outputs <- s::outputs 66 67 val mutable sub_clocks : Source.clock_variable list = [] 68 method attach_clock c = sub_clocks <- c::sub_clocks 69 method sub_clocks = sub_clocks 67 70 68 71 method end_tick = -
trunk/liquidsoap/src/clock.mli
r7194 r7195 25 25 method id : string 26 26 method attach : Source.active_source -> unit 27 method attach_clock : Source.clock_variable -> unit 28 method sub_clocks : Source.clock_variable list 27 29 method end_tick : unit 28 30 method start : unit … … 37 39 38 40 type clock_variable = Source.clock_variable 39 val create_unknown : Source.active_source list -> clock_variable 40 val create_known : clock -> clock_variable 41 val unify : clock_variable -> clock_variable -> bool 41 val to_string : clock_variable -> string 42 val create_unknown : sources:(Source.active_source list) -> 43 sub_clocks:(clock_variable list) -> 44 clock_variable 45 val create_known : clock -> clock_variable 46 val unify : clock_variable -> clock_variable -> unit -
trunk/liquidsoap/src/lang/lang.ml
r7171 r7195 626 626 Printf.printf "ERROR: %s!\n" s ; 627 627 exit 1 628 | Source.Clock_conflict (a,b) -> 629 (* TODO better printing of clock errors: we don't have position 630 * information, use the source's ID *) 631 Printf.printf 632 "An operator cannot belong to two clocks (%s, %s).\n" 633 a b ; 634 exit 1 635 | Source.Clock_loop (a,b) -> 636 Printf.printf 637 "Cannot unify two dependent clocks: %s, %s.\n" 638 a b ; 639 exit 1 628 640 | e -> print_error "Unknown error" ; raise e 629 641 -
trunk/liquidsoap/src/operators/cross.ml
r7052 r7195 2 2 3 3 Liquidsoap, a programmable stream generator. 4 Copyright 2003-20 09Savonet team4 Copyright 2003-2010 Savonet team 5 5 6 6 This program is free software; you can redistribute it and/or modify … … 43 43 inherit operator ~name:"cross" kind [s] as super 44 44 45 method stype = s#stype (* This actually depends on [f]. *) 45 method stype = s#stype (* This should actually depend on [f]. *) 46 47 val my_clock = new Clock.clock "cross_clock" 48 49 method set_clock = 50 let my_clock = Clock.create_known my_clock in 51 (* The source must belong to our clock, since we need occasional 52 * control on its flow (to fold an end of track over a beginning). *) 53 Clock.unify my_clock s#clock ; 54 (* Our external clock should stricly contain the internal my_clock. *) 55 Clock.unify 56 self#clock 57 (Clock.create_unknown ~sources:[] ~sub_clocks:[my_clock]) 46 58 47 59 (* The played source will be [s] at first, but can become a combination of … … 52 64 method private source_get ab = 53 65 source#get ab ; 66 (* TODO it might be abusive to end the tick all the time, 67 * maybe we didn't consume till the end of the current frame *) 68 my_clock#end_tick ; 69 (* TODO for now, we need to handle this (possibly passive) source 70 * ourselves since the clock only takes care of the active guys *) 54 71 source#after_output 55 72 56 val mutable activation = [] 57 58 method private wake_up activator = 59 activation <- (self:>source)::activator ; 60 s#get_ready ~dynamic:true activation ; 73 method private wake_up _ = 74 s#get_ready ~dynamic:true [(self:>source)] ; 61 75 source <- s ; 62 source#get_ready activation ; 63 Lang.iter_sources (fun s -> s#get_ready ~dynamic:true activation) f 76 source#get_ready [(self:>source)] ; 77 (* TODO when using f we'll have to force our clock on it *) 78 Lang.iter_sources (fun s -> s#get_ready ~dynamic:true [(self:>source)]) f 64 79 65 80 method private sleep = … … 175 190 in 176 191 source#leave (self:>source) ; 177 s#get_ready activation;192 s#get_ready [(self:>source)] ; 178 193 source <- s ; 179 194 status <- `After inhibit -
trunk/liquidsoap/src/source.ml
r7194 r7195 78 78 * are forced to wallclock. *) 79 79 80 class type ['a ] proto_clock =80 class type ['a,'b] proto_clock = 81 81 object 82 82 83 method id : string 84 85 (** Attach an active source. 86 * For now this only works before #start, but in a near future 87 * dynamic attaching/detaching should be supported. *) 83 88 method attach : 'a -> unit 89 90 (** Attach a sub_clock, get all subclocks, see below. *) 91 method attach_clock : 'b -> unit 92 method sub_clocks : 'b list 93 84 94 method start : unit 85 95 method stop : unit 96 86 97 end 87 98 88 99 (** {1 Clock variables} 89 * Used to infer what clock a source belongs to. *) 100 * Used to infer what clock a source belongs to. 101 * Each variable comes with 102 * - a list of active sources belonging to the clock, unused during 103 * inference/unification, but animated by the clock when running 104 * - a list of sub-clocks, used during unification's occurs-check 105 * to avoid cycles which would result in unsound behavior 106 * e.g. add([s,cross(f,s)]). 107 * Clock constants are objects of type proto_clock, but need to also 108 * maintain the information attached to variables. 109 * 110 * The unification algorithm can be described as follows, ignoring 111 * the active source maintenance. 112 * X[Y1,Y2,..,Yn] denotes a variable or constant clock with the set Gamma 113 * of subclocks, 114 * from a first-order unification perspective it should be thought of 115 * as a term X(Y1,Y2,..,Yn,...) where the second ... denotes a 116 * row variable: we don't know if there are more parameters there 117 * (more subclocks) 118 * We write X[Gamma] with Gamma list of clocks, and X[..Y..] when 119 * Y belongs to the subclocks of X, or the subclocks of the subclocks, 120 * etc. 121 * Unification rules are: 122 * X[..Y..] = Y[..] ---> ERROR (occurs-check) 123 * c1[...] = c2[...] ---> ERROR (rigid-rigid) 124 * X[Gamma] = Y[Delta] ---> X,Y:=Z[Gamma,Delta] 125 * Here Gamma,Delta denotes an union. It is possible that two 126 * distinct variables might become unified, in which case we'll 127 * end up with two occurrences of the same subclock. 128 *) 90 129 91 130 type 'a var = 92 131 | Link of 'a link_t ref 93 | Known of 'aproto_clock132 | Known of ('a,'a var) proto_clock 94 133 and 'a link_t = 95 | Unknown of 'a list 134 | Unknown of 'a list * 'a var list 96 135 | Same_as of 'a var 97 136 … … 108 147 Known c 109 148 110 let create_unknown l=111 let clock = Link (ref (Unknown l)) in149 let create_unknown ~sources ~sub_clocks = 150 let clock = Link (ref (Unknown (sources,sub_clocks))) in 112 151 clocks := clock :: !clocks ; 113 152 clock … … 119 158 let rec variable_to_string = function 120 159 | Link {contents=Same_as c} -> variable_to_string c 121 | Link ({contents=Unknown l} as r) -> 122 Printf.sprintf "?(%x:%d)" (Obj.magic r) (List.length l) 123 | Known c -> c#id 124 125 exception Clock_conflict 160 | Link ({contents=Unknown (sources,clocks)} as r) -> 161 Printf.sprintf "?(%x:%d)[%s]" 162 (Obj.magic r) 163 (List.length sources) 164 (String.concat "," (List.map variable_to_string clocks)) 165 | Known c -> 166 Printf.sprintf "%s[%s]" 167 c#id 168 (String.concat "," (List.map variable_to_string c#sub_clocks)) 169 170 (** Equality modulo dereferencing, does not identify two variables 171 * with the same sources and clocks. *) 172 let var_eq a b = 173 let a = deref a in 174 let b = deref b in 175 match a, b with 176 | Link a, Link b -> a==b 177 | Known a, Known b -> a=b 178 | _,_ -> false 179 180 exception Clock_conflict of string * string 181 exception Clock_loop of string * string 182 183 let rec sub_clocks = function 184 | Known c -> c#sub_clocks 185 | Link {contents = Unknown (_,sc)} -> sc 186 | Link {contents = Same_as x} -> sub_clocks x 187 188 let occurs_check x y = 189 let rec aux = function 190 | [] -> () 191 | []::tl -> aux tl 192 | (x'::clocks)::tl -> 193 if var_eq x x' then 194 raise (Clock_loop (variable_to_string x, variable_to_string y)) ; 195 aux (sub_clocks x' :: clocks :: tl) 196 in 197 aux [sub_clocks y] 198 199 let occurs_check x y = 200 occurs_check x y ; 201 occurs_check y x 126 202 127 203 let rec unify a b = … … 129 205 | Link {contents=Same_as a}, _ -> unify a b 130 206 | _, Link {contents=Same_as b} -> unify a b 131 | Known s, Known s' -> s = s' 132 | Link ({contents=Unknown la} as ra), Link ({contents=Unknown lb} as rb) -> 133 let merge = Link (ref (Unknown (la@lb))) in 207 | Known s, Known s' -> if s <> s' then 208 raise (Clock_conflict (variable_to_string a, variable_to_string b)) 209 | Link ({contents=Unknown (sa,ca)} as ra), 210 Link ({contents=Unknown (sb,cb)} as rb) -> 211 (* TODO perhaps optimize ca@cb *) 212 occurs_check a b ; 213 let merge = Link (ref (Unknown (sa@sb,ca@cb))) in 134 214 ra := Same_as merge ; 135 rb := Same_as merge ;136 true137 | Known c, Link ({contents=Unknown l} as r)138 | Link ({contents=Unknown l} as r), Known c ->139 List.iter c#attach l;140 r := Same_as (Known c);141 true215 rb := Same_as merge 216 | Known c, Link ({contents=Unknown (s,sc)} as r) 217 | Link ({contents=Unknown (s,sc)} as r), Known c -> 218 occurs_check (Known c) (Link r) ; 219 List.iter c#attach s ; 220 List.iter c#attach_clock sc ; 221 r := Same_as (Known c) 142 222 143 223 let assign_clocks ~default = … … 219 299 * changed anymore: a source lives in only one time flow. *) 220 300 221 val clock : active_source var = create_unknown []301 val clock : active_source var = create_unknown ~sources:[] ~sub_clocks:[] 222 302 223 303 method clock = clock 224 304 225 305 method set_clock = 226 List.iter 227 (fun s -> 228 if not (unify self#clock s#clock) then 229 raise Clock_conflict) 230 sources 306 List.iter (fun s -> unify self#clock s#clock) sources 231 307 232 308 (** Startup/shutdown. … … 439 515 has_outputs := true ; 440 516 ignore 441 (unify self#clock (create_unknown [(self:>active_source)])) ; 517 (unify 518 self#clock 519 (create_unknown ~sources:[(self:>active_source)] ~sub_clocks:[])) ; 442 520 self#set_sources [] 443 521 … … 481 559 method id : string 482 560 method attach : active_source -> unit 561 method attach_clock : clock_variable -> unit 562 method sub_clocks : clock_variable list 483 563 method start : unit 484 564 method stop : unit -
trunk/liquidsoap/src/source.mli
r7194 r7195 151 151 val has_outputs : unit -> bool 152 152 153 (** {1 Clocks} *) 154 153 155 class type clock = 154 156 object 155 157 method id : string 156 158 method attach : active_source -> unit 159 157 160 method start : unit 158 161 method stop : unit 162 163 method attach_clock : clock_variable -> unit 164 method sub_clocks : clock_variable list 159 165 end 160 166 161 exception Clock_conflict 167 exception Clock_conflict of string*string 168 exception Clock_loop of string*string 162 169 163 170 module Clock_variables : 164 171 sig 165 172 val to_string : clock_variable -> string 166 val create_unknown : active_source list -> clock_variable 167 val create_known : clock -> clock_variable 168 val unify : clock_variable -> clock_variable -> bool 173 val create_unknown : sources:(active_source list) -> 174 sub_clocks:(clock_variable list) -> 175 clock_variable 176 val create_known : clock -> clock_variable 177 val unify : clock_variable -> clock_variable -> unit 169 178 val get_clocks : default:clock -> clock list 170 179 end
