12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061(* 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 Paula.mli *)typereading=Hold|Linear|Cubicletreadings=[Hold;Linear;Cubic]letreading_name=functionHold->"hold (Paula's)"|Linear->"linear"|Cubic->"cubic"(* the sample, where in it (in bytes, fractional), the loop, the period,
* the volume; silent when [sample] is empty *)typet={mutablesample:Signal.t;mutablepos:float;mutableloop_start:int;mutableloop_length:int;mutableperiod:int;mutablevolume:int;}letcreate():t={sample=[||];pos=0.;loop_start=0;loop_length=0;period=428;volume=64}lettrigger(c:t)(sample:Signal.t)~(loop_start:int)~(loop_length:int)~(offset:int):unit=c.sample<-sample;c.pos<-float_of_intoffset;c.loop_start<-loop_start;c.loop_length<-loop_lengthletset_period(c:t)(p:int):unit=ifp>0thenc.period<-pletset_volume(c:t)(v:int):unit=c.volume<-max0(min64v)letstop(c:t):unit=c.sample<-[||]letplaying(c:t):bool=Array.lengthc.sample>0letnext(reading:reading)(c:t):float=letn=Array.lengthc.sampleinifn=0then0.else(* past the loop's end, back by its length; past the sample's end
* with no loop, silent *)letloop_end=c.loop_start+c.loop_lengthinifc.loop_length>0&&c.pos>=float_of_intloop_endthenc.pos<-c.pos-.float_of_intc.loop_length;ifc.pos>=float_of_intnthen(c.sample<-[||];0.)elseletx=matchreadingwith|Hold->c.sample.(int_of_floatc.pos)|Linear->Resample.readLinearc.samplec.pos|Cubic->Resample.readCubicc.samplec.posinc.pos<-c.pos+.(Mod.paula_clock/.float_of_intc.period/.float_of_intSignal.rate);x*.float_of_intc.volume/.64.