-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Strudelize Hazel #1395
base: dev
Are you sure you want to change the base?
Strudelize Hazel #1395
Conversation
…functionalized strudel DSL (currently just Note)
let exampleUse: unit => unit = | ||
() => { | ||
initStrudel(); | ||
playNote("<c a f e>(3,8)"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
☕
@7h3kk1d did you look into the below style of binding js fns when doing the ninjakeys thing? claude suggested it but i couldn't get it to work properly. interestingly, different errors on dev and release. in dev, it was trying to access the fns on an object called
|
I don't think I tried the bucklescript annotation. There was another syntax that I couldn't use because my function was called |
let initStrudel: unit => unit = | ||
() => { | ||
let initStrudelFn = Js.Unsafe.js_expr("window.initStrudel"); | ||
Js.Unsafe.fun_call(initStrudelFn, [||]); | ||
}; | ||
|
||
let hush: unit => unit = | ||
() => { | ||
let hushFn = Js.Unsafe.js_expr("window.hush"); | ||
Js.Unsafe.fun_call(hushFn, [||]); | ||
}; | ||
|
||
let note: string => Js.Unsafe.any = | ||
pattern => { | ||
let noteFn = Js.Unsafe.js_expr("window.note"); | ||
Js.Unsafe.fun_call(noteFn, [|Js.Unsafe.inject(Js.string(pattern))|]); | ||
}; | ||
|
||
let rev: Js.Unsafe.any => Js.Unsafe.any = | ||
pattern => { | ||
let revFn = Js.Unsafe.js_expr("window.rev"); | ||
Js.Unsafe.fun_call(revFn, [|Js.Unsafe.inject(pattern)|]); | ||
}; | ||
|
||
let jux: (Js.Unsafe.any, Js.Unsafe.any => Js.Unsafe.any) => Js.Unsafe.any = | ||
(pattern, f) => { | ||
Js.Unsafe.meth_call(pattern, "jux", [|Js.Unsafe.inject(f)|]); | ||
}; | ||
|
||
let play: Js.Unsafe.any => unit = | ||
pattern => { | ||
Js.Unsafe.meth_call(pattern, "play", [||]); | ||
}; | ||
|
||
/* Wrapper function to chain methods */ | ||
let playNote: string => unit = | ||
pattern => { | ||
let n = note(pattern); | ||
let j = jux(n, rev); | ||
play(j); | ||
}; | ||
|
||
/* Example usage function */ | ||
let exampleUse: unit => unit = | ||
() => { | ||
initStrudel(); | ||
playNote("<c a f e>(3,8)"); | ||
}; | ||
|
||
/* Function to stop the music */ | ||
let stopMusic: unit => unit = () => hush(); | ||
|
||
/* Function to initialize Strudel when the DOM is loaded */ | ||
let initOnLoad: unit => unit = | ||
() => { | ||
let addEventListenerFn = Js.Unsafe.js_expr("window.addEventListener"); | ||
Js.Unsafe.fun_call( | ||
addEventListenerFn, | ||
[| | ||
Js.Unsafe.inject(Js.string("DOMContentLoaded")), | ||
Js.Unsafe.inject(Js.wrap_callback(_ => initStrudel())), | ||
|], | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let initStrudel: unit => unit = | |
() => { | |
let initStrudelFn = Js.Unsafe.js_expr("window.initStrudel"); | |
Js.Unsafe.fun_call(initStrudelFn, [||]); | |
}; | |
let hush: unit => unit = | |
() => { | |
let hushFn = Js.Unsafe.js_expr("window.hush"); | |
Js.Unsafe.fun_call(hushFn, [||]); | |
}; | |
let note: string => Js.Unsafe.any = | |
pattern => { | |
let noteFn = Js.Unsafe.js_expr("window.note"); | |
Js.Unsafe.fun_call(noteFn, [|Js.Unsafe.inject(Js.string(pattern))|]); | |
}; | |
let rev: Js.Unsafe.any => Js.Unsafe.any = | |
pattern => { | |
let revFn = Js.Unsafe.js_expr("window.rev"); | |
Js.Unsafe.fun_call(revFn, [|Js.Unsafe.inject(pattern)|]); | |
}; | |
let jux: (Js.Unsafe.any, Js.Unsafe.any => Js.Unsafe.any) => Js.Unsafe.any = | |
(pattern, f) => { | |
Js.Unsafe.meth_call(pattern, "jux", [|Js.Unsafe.inject(f)|]); | |
}; | |
let play: Js.Unsafe.any => unit = | |
pattern => { | |
Js.Unsafe.meth_call(pattern, "play", [||]); | |
}; | |
/* Wrapper function to chain methods */ | |
let playNote: string => unit = | |
pattern => { | |
let n = note(pattern); | |
let j = jux(n, rev); | |
play(j); | |
}; | |
/* Example usage function */ | |
let exampleUse: unit => unit = | |
() => { | |
initStrudel(); | |
playNote("<c a f e>(3,8)"); | |
}; | |
/* Function to stop the music */ | |
let stopMusic: unit => unit = () => hush(); | |
/* Function to initialize Strudel when the DOM is loaded */ | |
let initOnLoad: unit => unit = | |
() => { | |
let addEventListenerFn = Js.Unsafe.js_expr("window.addEventListener"); | |
Js.Unsafe.fun_call( | |
addEventListenerFn, | |
[| | |
Js.Unsafe.inject(Js.string("DOMContentLoaded")), | |
Js.Unsafe.inject(Js.wrap_callback(_ => initStrudel())), | |
|], | |
); | |
}; | |
let initStrudel: unit => unit = | |
() => Js.Unsafe.coerce(Dom_html.window)##initStrudel(); | |
let hush: unit => unit = | |
() => { | |
Js.Unsafe.coerce(Dom_html.window)##hush(); | |
}; | |
let note: string => Js.Unsafe.any = | |
pattern => { | |
Js.Unsafe.coerce(Dom_html.window)##note(Js.string(pattern)); | |
}; | |
let rev: Js.Unsafe.any => Js.Unsafe.any = | |
pattern => { | |
Js.Unsafe.coerce(Dom_html.window)##rev(pattern); | |
}; | |
let jux: (Js.Unsafe.any, Js.Unsafe.any => Js.Unsafe.any) => Js.Unsafe.any = | |
(pattern, f) => { | |
Js.Unsafe.coerce(pattern)##jux(f); | |
}; | |
let play: Js.Unsafe.any => unit = | |
pattern => { | |
Js.Unsafe.coerce(pattern)##play(); | |
}; | |
/* Wrapper function to chain methods */ | |
let playNote: string => unit = | |
pattern => { | |
let n = note(pattern); | |
let j = jux(n, rev); | |
play(j); | |
}; | |
/* Example usage function */ | |
let exampleUse: unit => unit = | |
() => { | |
initStrudel(); | |
playNote("<c a f e>(3,8)"); | |
}; | |
/* Function to stop the music */ | |
let stopMusic: unit => unit = () => hush(); | |
/* Function to initialize Strudel when the DOM is loaded */ | |
let initOnLoad: unit => Dom_events.listener = | |
() => { | |
Dom_events.listen( | |
Dom_html.window, | |
Dom_events.Typ.domContentLoaded, | |
(_: Js.t(Dom_html.window), _: Js.t(Dom_html.event)) => { | |
initStrudel(); | |
false; // I don't think this does anything. | |
}, | |
); | |
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The false
being returned on the Dom_events.listen
looks like it would be used for stop propagation but I looked through the js_of_ocaml implementation and I don't see where this is happening.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I take it back https://github.com/ocsigen/js_of_ocaml/blob/ea51f5e6e1c54a13eb917d081c51175814b8b58b/lib/js_of_ocaml/dom_events.ml#L32 the newest version calls full_handler which does prevent_default so probably set that to true
This wraps some Strudel functions in order to create audio in Hazel. Right now, it wraps only the Note function, which takes a string corresponding to a Strudel/TidalCycles cycle. This is an eDSL string which can take a space-separated list of notes (a-g), and a variety of other notations. Everything in the string is played over a second, so the more notes the faster it is.
Should be functional now on the build server; see docs/sounds:
The plan is to wrap a few more functions, defunctionalizing to create a simple ADT corresponding to Strudel code. This could be used as a basis for a future more elaborate eDSL using projectors/livelits.
Right now, audio plays whenever the program evaluates to a Note. It can be stopped via a button, and the playing audio restarts every time a valid Strudel program is returned, which is different than the last valid Strudel program for which playing began