Skip to content

Instantly share code, notes, and snippets.

@jellea
Last active May 3, 2017 08:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jellea/79f0aa83c67132c59317c2ee3b30134f to your computer and use it in GitHub Desktop.
Save jellea/79f0aa83c67132c59317c2ee3b30134f to your computer and use it in GitHub Desktop.
open ReasonJs;
type uint8Array;
external int8Array : int => uint8Array = "window.Uint8Array" [@@bs.new];
external get : uint8Array => int => int = "" [@@bs.get_index];
[%%bs.raw{|
window.polyAudioContext = window.AudioContext || new window.webkitAudioContext
|}];
let module Window = {
type window;
external get_inner_width : window => int = "innerWidth" [@@bs.get];
external get_inner_height : window => int = "innerHeight" [@@bs.get];
external get_window: window = "window" [@@bs.val];
external width: int = "window.innerWidth" [@@bs.val];
external height: int = "window.innerHeight" [@@bs.val];
};
let module Document = {
type element;
external query_selector : string => element = "document.querySelector" [@@bs.val];
external getWidth : element => int = "width" [@@bs.get];
external getHeight : element => int = "height" [@@bs.get];
external request_animation_frame : (unit => unit) => unit = "window.requestAnimationFrame" [@@bs.val];
external play_audio : element => 'promise = "play" [@@bs.send];
external set_height : element => int => unit = "height" [@@bs.set];
external set_width: element => int => unit = "width" [@@bs.set];
external get_height : element => int = "height" [@@bs.get];
external get_width : element => int = "width" [@@bs.get];
};
let module AudioNode = {
type audioNode;
type mediaElementSourceNode = audioNode;
type analyzerNode = audioNode;
external connect : audioNode => audioNode => unit = "connect" [@@bs.send];
external get_byte_frequency_data : analyzerNode => uint8Array => array int = "getByteFrequencyData" [@@bs.send];
external get_byte_time_domain_data : analyzerNode => uint8Array => array int = "getByteTimeDomainData" [@@bs.send];
external fft_size : analyzerNode => int = "fftSize" [@@bs.get];
external fft_size : analyzerNode => int => unit = "fftSize" [@@bs.set];
external frequency_bin_count : analyzerNode => int = "frequencyBinCount" [@@bs.get];
};
let module AudioContext = {
type audioContext;
external destination : audioContext => AudioNode.audioNode = "destination" [@@bs.get];
external create_audio_context : audioContext = "window.polyAudioContext" [@@bs.val];
external create_analyzer : audioContext => AudioNode.analyzerNode = "createAnalyser" [@@bs.send];
external create_media_element_source : audioContext => Document.element => AudioNode.mediaElementSourceNode = "createMediaElementSource" [@@bs.send];
};
let module Canvas = {
type canvasContext;
external fill_style : canvasContext => string => unit = "fillStyle" [@@bs.set];
external fill_rect : canvasContext => int => int => int => int => unit = "fillRect" [@@bs.send];
external line_width : canvasContext => int => unit = "lineWidth" [@@bs.set];
external stroke_style : canvasContext => string => unit = "strokeStyle" [@@bs.set];
external begin_path : canvasContext => unit = "beginPath" [@@bs.send];
external stroke : canvasContext => unit = "stroke" [@@bs.send];
external move_to : canvasContext => float => float => unit = "moveTo" [@@bs.send];
external line_to : canvasContext => float => float => unit = "lineTo" [@@bs.send];
external get_context : Document.element => string => canvasContext = "getContext" [@@bs.send];
};
let my_audio = Document.query_selector "#audio-one";
let context = AudioContext.create_audio_context;
let player = AudioContext.create_media_element_source context my_audio;
let analyzer = AudioContext.create_analyzer context;
let _ = AudioNode.fft_size analyzer 512;
let buffer_length = AudioNode.frequency_bin_count analyzer;
let time_data_array = int8Array buffer_length;
let freq_data_array = int8Array buffer_length;
AudioNode.connect player (AudioContext.destination context);
AudioNode.connect player (analyzer);
Document.play_audio my_audio;
let canvas = Document.query_selector "#bg-canvas";
let canvas_ctx = Canvas.get_context canvas "2d";
let window_height = Window.height;
let window_width = Window.width;
let canvas_width = window_width - 100;
let canvas_height = window_height - 100;
let _ = Document.set_height canvas canvas_height;
let _ = Document.set_width canvas canvas_width;
let draw_oscillator_frame (off_x, off_y, width, height) => {
Canvas.fill_style canvas_ctx "rgb(144,221,203)";
Canvas.fill_rect canvas_ctx off_x off_y width height;
Canvas.line_width canvas_ctx 1;
Canvas.stroke_style canvas_ctx "rgb(255,255,255)";
let slice_width = float(width) *. 1.0 /. float buffer_length;
Canvas.begin_path canvas_ctx;
for x in 0 to buffer_length {
let v = float(get time_data_array x) /. 128.0;
let y = float(off_y) +. v *. float(height) /. 2.0 ;
let new_x = float(off_x) +. float(x) *. slice_width;
if(x === 0) {
Canvas.move_to canvas_ctx new_x y;
} else {
Canvas.line_to canvas_ctx new_x y;
};
};
Canvas.line_to canvas_ctx
(float(off_x) +. ceil(float(width)))
(float(off_y) +. ceil(float(height) /. 2.));
Canvas.stroke canvas_ctx;
};
let draw_freq_spectrum_frame (off_x, off_y, width, height) => {
Canvas.fill_style canvas_ctx "rgb(144,221,203)";
Canvas.fill_rect canvas_ctx off_x off_y width height;
Canvas.line_width canvas_ctx 1;
Canvas.stroke_style canvas_ctx "rgb(255,255,255)";
let slice_width = float(width) *. 1.0 /. float buffer_length;
Canvas.begin_path canvas_ctx;
for x in 0 to buffer_length {
let v = float(get freq_data_array x) /. 128.0;
let y = float(off_y) +. v *. float(height);
let new_x = float(off_x) +. float(x) *. slice_width;
if(x === 0) {
Canvas.move_to canvas_ctx new_x y;
} else {
Canvas.line_to canvas_ctx new_x y;
};
};
Canvas.line_to canvas_ctx
(float(off_x) +. ceil(float(width)))
(float(off_y) +. ceil(float(height) /. 2.));
Canvas.stroke canvas_ctx;
};
let rec render unit => {
let _ = AudioNode.get_byte_time_domain_data analyzer time_data_array;
let _ = AudioNode.get_byte_frequency_data analyzer freq_data_array;
/* first row */
draw_oscillator_frame(0, 0, canvas_width/3-30, canvas_height/3-30);
draw_freq_spectrum_frame(canvas_width/3*2, 0, canvas_width/3-30, canvas_height/3-30);
draw_oscillator_frame(canvas_width/3, 0, canvas_width/3-30, canvas_height/3-30);
/* second row */
draw_oscillator_frame(0, canvas_height/3, canvas_width/3*2-30, canvas_height/3-30);
draw_oscillator_frame(canvas_width/3*2, canvas_height/3, canvas_width/3-30, canvas_height/3-30);
/* third row */
draw_oscillator_frame(0, canvas_height/3*2, canvas_width/3-30, canvas_height/3-30);
draw_oscillator_frame(canvas_width/3, canvas_height/3*2, canvas_width/3-30, canvas_height/3-30);
draw_oscillator_frame(canvas_width/3*2, canvas_height/3*2, canvas_width/3-30, canvas_height/3-30);
Document.request_animation_frame render;
};
Document.request_animation_frame render;
/*
let myInterval = ReasonJs.setInterval (fun () => ReasonJs.Console.log "hello!") 1000; */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment