package tiny_libs
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
From-scratch libraries for teaching: graphics, audio, compression, crypto, networking and more
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.3.6.tar.gz
md5=7c636383d146d30ac6f2fa234a6253c8
sha512=c79f3823c5f8f57e5038eb640d487c61168b84aa07c61999d6622ef9fd0c890e2b03b4c6a7cdbbe9352a49e25dda00ac7bb14693cee8e3d7beeed251351a2af0
doc/src/tiny_libs.audio_instruments/Vco.ml.html
Source file Vco.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91(* 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 Vco.mli *) type shape = Sine | Triangle | Sawtooth | Pulse let shapes = [ Sine; Triangle; Sawtooth; Pulse ] let name = function Sine -> "sine" | Triangle -> "triangle" | Sawtooth -> "sawtooth" | Pulse -> "pulse" (* the phase; for a master, where in each step of the last block it * wrapped (the fraction of the step, or -1); for a slave, the second * half of a restart's correction, due at the next sample (h, d) *) type t = { mutable phase : float; mutable wraps : float array; mutable due : (float * float) option } let create () : t = { phase = 0.; wraps = [||]; due = None } let naive (shape : shape) ~(width : float) (phase : float) : float = match shape with | Sine -> Oscillator.wave Sine phase | Triangle -> Oscillator.wave Triangle phase | Sawtooth -> Oscillator.wave Sawtooth phase | Pulse -> Oscillator.pulse ~width phase let band_limited_wave (shape : shape) ~(width : float) ~(dt : float) (phase : float) : float = match shape with | Sine -> Oscillator.wave Sine phase | Triangle -> Oscillator.wave_band_limited Triangle ~dt phase | Sawtooth -> Oscillator.wave_band_limited Sawtooth ~dt phase | Pulse -> Oscillator.pulse_band_limited ~width ~dt phase (* the correction of the wave's own jump at phase 0 (the sawtooth's * down, the pulse's up), to leave out where a restart replaced it *) let own_jump (shape : shape) ~(dt : float) (phase : float) : float = match shape with | Sawtooth -> -.Oscillator.polyblep ~dt phase | Pulse -> Oscillator.polyblep ~dt phase | Sine | Triangle -> 0. let wrap (x : float) : float = x -. Float.floor x type restart = Fraction | At_sample let run ~(band_limited : bool) ~(restart : restart) ?width ?sync (t : t) (shape : shape) ~(frequency : Signal.t) (out : Signal.t) : unit = let n = Array.length out in if Array.length t.wraps <> n then t.wraps <- Array.make n (-1.); for i = 0 to n - 1 do let dt = frequency.(i) /. float_of_int Signal.rate in let width = match width with None -> 0.5 | Some w -> Float.min 0.99 (Float.max 0.01 w.(i)) in let p = t.phase in let x = ref (if band_limited then band_limited_wave shape ~width ~dt p else naive shape ~width p) in (* the second half of the last step's restart *) (match t.due with | Some (h, d) -> x := !x +. (h /. 2. *. ((2. *. d) -. (d *. d) -. 1.)) -. own_jump shape ~dt p; t.due <- None | None -> ()); (* restarted before the next sample? at [f], a fraction of the step *) let restart_at = match sync with Some m when i < Array.length m.wraps -> m.wraps.(i) | _ -> -1. in if restart_at >= 0. then ( let f = match restart with Fraction -> restart_at | At_sample -> 1. in let d = 1. -. f in let before = naive shape ~width (wrap (p +. (f *. dt))) and after = naive shape ~width 0. in let h = after -. before in if band_limited then ( (* its own jump, if it was coming in this step, won't: the * restart comes first *) if p +. (f *. dt) < 1. then x := !x -. own_jump shape ~dt p; x := !x +. (h /. 2. *. d *. d); t.due <- Some (h, d)); t.wraps.(i) <- f; t.phase <- d *. dt) else ( t.wraps.(i) <- (if p +. dt >= 1. then (1. -. p) /. dt else -1.); t.phase <- wrap (p +. dt)); out.(i) <- !x done let fill ?(band_limited = true) ?width ?sync t shape ~frequency out = run ~band_limited ~restart:Fraction ?width ?sync t shape ~frequency out let fill_sync_at_sample ?width ~sync t shape ~frequency out = run ~band_limited:true ~restart:At_sample ?width ~sync t shape ~frequency out
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>