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_synthesis/Oscillator.ml.html
Source file Oscillator.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(* 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 Oscillator.mli *) type waveform = Sine | Square | Triangle | Sawtooth let waveforms = [ Sine; Square; Triangle; Sawtooth ] let name = function Sine -> "sine" | Square -> "square" | Triangle -> "triangle" | Sawtooth -> "sawtooth" let wave (w : waveform) (phase : float) : float = match w with | Sine -> sin (2. *. Float.pi *. phase) | Square -> if phase < 0.5 then 1. else -1. (* 0 up to 1 at a quarter, down to -1 at three quarters, back to 0: * in step with the sine *) | Triangle -> if phase < 0.25 then 4. *. phase else if phase < 0.75 then 2. -. (4. *. phase) else (4. *. phase) -. 4. | Sawtooth -> (2. *. phase) -. 1. let polyblep ~(dt : float) (t : float) : float = if t < dt then let u = t /. dt in (2. *. u) -. (u *. u) -. 1. else if t > 1. -. dt then let u = (t -. 1.) /. dt in (u *. u) +. (2. *. u) +. 1. else 0. (* the integral of polyblep's residual for a unit step, (u+1)^3 / 6 * before, (1-u)^3 / 6 after: 1/6 at the corner *) let polyblamp ~(dt : float) (t : float) : float = if t < dt then let u = 1. -. (t /. dt) in u *. u *. u /. 6. else if t > 1. -. dt then let u = ((t -. 1.) /. dt) +. 1. in u *. u *. u /. 6. else 0. let wrap (phase : float) : float = phase -. Float.floor phase let wave_band_limited (w : waveform) ~(dt : float) (phase : float) : float = match w with | Sine -> wave w phase (* corners at 0.25 (the slope from +4 to -4 a period: -8 dt a sample) * and 0.75 (back up, +8 dt) *) | Triangle -> wave w phase -. (8. *. dt *. polyblamp ~dt (wrap (phase -. 0.25))) +. (8. *. dt *. polyblamp ~dt (wrap (phase -. 0.75))) (* up at 0, down at 0.5 *) | Square -> wave w phase +. polyblep ~dt phase -. polyblep ~dt (wrap (phase +. 0.5)) (* down at 0 *) | Sawtooth -> wave w phase -. polyblep ~dt phase let pulse ~(width : float) (phase : float) : float = (if phase < width then 1. else -1.) -. ((2. *. width) -. 1.) (* up at 0, down at [width] *) let pulse_band_limited ~(width : float) ~(dt : float) (phase : float) : float = pulse ~width phase +. polyblep ~dt phase -. polyblep ~dt (wrap (phase -. width)) type t = { waveform : waveform; frequency : float; phase : float } let make (waveform : waveform) (frequency : float) : t = { waveform; frequency; phase = 0. } let next ?(band_limited = false) (o : t) : float * t = let dt = o.frequency /. float_of_int Signal.rate in let phase = o.phase +. dt in let x = if band_limited then wave_band_limited o.waveform ~dt o.phase else wave o.waveform o.phase in (x, { o with phase = phase -. Float.floor phase }) let render ?band_limited (w : waveform) ~(frequency : float) (seconds : float) : Signal.t = let o = ref (make w frequency) in Array.init (Signal.samples seconds) (fun _ -> let (x, o') = next ?band_limited !o in o := o'; x)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>