1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162(* Claude Code
*
* Copyright (C) 2026 Yoann Padioleau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* (LGPL) as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*)(* See Voicing.mli *)typepriority=Low|High|Lasttypeevent=Beginofint|Changeofint|End|Nothing(* the keys held, the last pressed first *)typet={priority:priority;retrigger:bool;mutableheld:intlist}letcreate?(priority=Last)?(retrigger=false)():t={priority;retrigger;held=[]}letsounding(t:t):intoption=match(t.held,t.priority)with|[],_->None|last::_,Last->Somelast|keys,Low->Some(List.fold_leftminmax_intkeys)|keys,High->Some(List.fold_leftmaxmin_intkeys)(* from what sounded before to what sounds now *)letevent(t:t)(before:intoption):event=match(before,soundingt)with|_,None->ifbefore=NonethenNothingelseEnd|None,Somen->Beginn|Someb,Somenwhenb=n->Nothing|Some_,Somen->ift.retriggerthenBeginnelseChangenletpress(t:t)(key:int):event=letbefore=soundingtint.held<-key::List.filter((<>)key)t.held;eventtbeforeletrelease(t:t)(key:int):event=letbefore=soundingtint.held<-List.filter((<>)key)t.held;eventtbeforetypeglide={mutablepitch:float;mutabletarget:float}letglide?(note=60.)():glide={pitch=note;target=note}letglide_to(g:glide)(note:int):unit=g.target<-float_of_intnoteletpitch(g:glide):float=g.pitchletfrequency(pitch:float):float=440.*.Float.pow2.((pitch-.69.)/.12.)letfill_pitch(g:glide)~(seconds:float)(out:Signal.t):unit=letc=ifseconds<=0.then1.else1.-.exp(-1./.(seconds*.float_of_intSignal.rate))infori=0toArray.lengthout-1dog.pitch<-g.pitch+.((g.target-.g.pitch)*.c);out.(i)<-g.pitchdoneletfill_frequency(g:glide)~(seconds:float)(out:Signal.t):unit=fill_pitchg~secondsout;Array.iteri(funip->out.(i)<-frequencyp)out