Advertisement
Guest User

Untitled

a guest
May 24th, 2017
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.35 KB | None | 0 0
  1. open Containers;
  2.  
  3. external pow : float => float => float = "Math.pow" [@@bs.val];
  4. external requestAnimationFrame : (unit => unit) => unit = "window.requestAnimationFrame" [@@bs.val];
  5.  
  6. module rec AudioContext: {
  7. type destination;
  8. type t = Js.t {
  9. .
  10. destination : destination,
  11. sampleRate : float,
  12. createBufferSource [@bs.meth] : unit => AudioBufferSource.t,
  13. createBuffer [@bs.meth] : int => int => float => AudioBuffer.t,
  14. currentTime : float
  15. };
  16.  
  17. external make : unit => t = "window.AudioContext" [@@bs.new];
  18. } = AudioContext
  19. and AudioBuffer: {
  20. type t = Js.t {
  21. .
  22. copyToChannel [@bs.meth]: Js_typed_array.Float32Array.t => int => int => unit
  23. };
  24. } = AudioBuffer
  25. and AudioBufferSource: {
  26. type t;
  27.  
  28. external connect : t => AudioContext.destination => unit = "connect" [@@bs.send];
  29. external setBuffer : t => AudioBuffer.t => unit = "buffer" [@@bs.set];
  30. external start : t => float => unit = "start" [@@bs.send];
  31. external stop : t => float => unit = "stop" [@@bs.send];
  32. } = AudioBufferSource;
  33.  
  34. module Synth = {
  35. type octave = float;
  36. type duration = float;
  37. type pitch = C | Cs | D | Ds | E | F | Fs | G | Gs | A | As | B;
  38. type note = Note pitch octave duration | Rest duration;
  39. type noteArray = Js_typed_array.Float32Array.t;
  40.  
  41. module Notes = Map.Make({ type t = pitch; let compare = compare; });
  42.  
  43. let notes = Notes.fromList [
  44. (C, 16.35),
  45. (Cs, 17.32),
  46. (D, 18.35),
  47. (Ds, 19.45),
  48. (E, 20.60),
  49. (F, 21.83),
  50. (Fs, 23.12),
  51. (G, 24.50),
  52. (Gs, 25.96),
  53. (A, 27.50),
  54. (As, 29.14),
  55. (B, 30.87),
  56. ];
  57.  
  58. let makeNote : AudioContext.t => note => AudioBuffer.t = fun ctx note => {
  59. switch note {
  60. | Note pitch octave duration => {
  61. let length = truncate @@ duration *. ctx##sampleRate;
  62. let c = ctx##createBuffer 2 (length) ctx##sampleRate;
  63. let freq = (pow 2.0 octave) *. Notes.find pitch notes;
  64. let noteDivisor = (ctx##sampleRate /. freq);
  65. let b = Array.make length 1.0
  66. |> Array.mapi (fun i _ => Js_math.sin (3.1415 *. 2.0 *. (float i) /. noteDivisor))
  67. |> Js_typed_array.Float32Array.make;
  68.  
  69. c##copyToChannel b 0 0;
  70. c##copyToChannel b 1 0;
  71. c;
  72. }
  73. | Rest duration => {
  74. let length = truncate @@ duration *. ctx##sampleRate;
  75. let c = ctx##createBuffer 2 (length) ctx##sampleRate;
  76. let b = Array.make length 0.0
  77. |> Js_typed_array.Float32Array.make;
  78. c##copyToChannel b 0 0;
  79. c##copyToChannel b 1 0;
  80. c;
  81. }
  82. }
  83. };
  84.  
  85. let stop = fun source time => {
  86. AudioBufferSource.stop source time;
  87. };
  88.  
  89. let play : AudioContext.t => AudioBuffer.t => float => AudioBufferSource.t = fun audioCtx c time => {
  90. let source = audioCtx##createBufferSource ();
  91.  
  92. AudioBufferSource.setBuffer source c;
  93. AudioBufferSource.connect source audioCtx##destination;
  94. AudioBufferSource.start source time;
  95. source;
  96. };
  97. };
  98.  
  99. let audioCtx = AudioContext.make ();
  100. let start = audioCtx##currentTime +. 0.05;
  101. let spn = 60.0 /. 80.0;
  102.  
  103. let rec schedule (currentEnd, playing) (duration, source) list => {
  104. let currentTime = audioCtx##currentTime -. start;
  105.  
  106. if (currentEnd < currentTime +. 0.25) {
  107. Synth.stop playing (currentEnd);
  108. let nowPlaying = Synth.play audioCtx source currentEnd;
  109.  
  110. if (List.length list > 0) {
  111. let [(n1, n2), ...rest] = list;
  112. requestAnimationFrame (fun _ => schedule (spn *. duration +. currentTime, nowPlaying) (n1, n2) rest);
  113. } else {
  114. Synth.stop nowPlaying (currentEnd +. duration *. spn);
  115. };
  116. } else {
  117. requestAnimationFrame (fun _ => schedule (currentEnd, playing) (duration, source) list);
  118. };
  119. };
  120.  
  121. let main song => {
  122. switch song {
  123. | [] => ()
  124. | [(d, s)] => {
  125. let x = Synth.play audioCtx s start;
  126. }
  127. | [(d, s), (d', s'), ...rest] => {
  128. let x = Synth.play audioCtx s start;
  129. schedule (start +. d *. spn, x) (d', s') rest;
  130. }
  131. };
  132. };
  133.  
  134. let f = fun x => {
  135. switch x {
  136. | Synth.Note n o d => (d, Synth.makeNote audioCtx (Note n o d))
  137. | Synth.Rest d => (d, Synth.makeNote audioCtx (Rest d))
  138. };
  139. };
  140.  
  141. main @@ List.map f [
  142. Synth.Note E 4.0 1.0,
  143. Synth.Note E 4.0 1.0,
  144. Synth.Note F 4.0 1.0,
  145. Synth.Note G 4.0 1.0,
  146. Synth.Note G 4.0 1.0,
  147. Synth.Note F 4.0 1.0,
  148. Synth.Note E 4.0 1.0,
  149. Synth.Note D 4.0 1.0,
  150. Synth.Note C 4.0 1.0,
  151. Synth.Note C 4.0 1.0,
  152. Synth.Note D 4.0 1.0,
  153. Synth.Note E 4.0 1.0,
  154. Synth.Note E 4.0 1.75,
  155. Synth.Note D 4.0 0.25,
  156. Synth.Note D 4.0 1.0,
  157. ];
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement