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
type shape = Sine | Triangle | Sawtooth | Pulse
let shapes = [ Sine; Triangle; Sawtooth; Pulse ]
let name = function Sine -> "sine" | Triangle -> "triangle" | Sawtooth -> "sawtooth" | Pulse -> "pulse"
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
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
(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 -> ());
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 (
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