Skip to content
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

Add integration from Strudel patterns and canvas into hydra #309

Merged
merged 8 commits into from
Jan 1, 2025
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,21 @@ the `hydra` target to execute Hydra code.
You can also use [p5.js](https://p5js.org/) within a `hydra` target, like you would in
the official Hydra editor.

##### `P()` function
The `P()` function allows you to use strudel mini-patterns in Hydra.
It uses the same timing information as Strudel itself, so it will be synchronized with the audio.

**Note**: It will only work, if strudel is already initialized, because that will load the modules we need.
**Note**: You can not use any strudel functions on the pattern.
**Note**: Currently we do not have mini-highlighting for Hydra panes.

##### `useStrudelCanvas(source)`

Will initialise the given source (`s0`, `s1`, etc) to use the strudel canvas as a source.
Will also hide the strudel canvas, so it will not overlap.

**Note**: Strudel will have to be initialized, otherwise this will not work.

##### `fft()` function

The `fft()` function is a special function that allows you to get the FFT data
Expand Down
29 changes: 29 additions & 0 deletions packages/web/src/lib/hydra-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ declare global {
H: Function;
P5: Function;
fft: (index: number, buckets: number) => number;
P: Function;
useStrudelCanvas: Function;
}
}

Expand Down Expand Up @@ -74,6 +76,33 @@ export class HydraWrapper {

window.H = this._hydra;

// Enable using strudel style mini-patterns for argument control on Hydra.
// strudel needs to be loaded first, otherwise this will cause warnings, and rendering will not
// include the mini-pattern.
// Inspired by
// - https://github.com/atfornes/Hydra-strudel-extension/blob/51a93496b1b05ea00c08d1dec10e046aa3769c93/hydra-strudel.js#L72
// - https://github.com/tidalcycles/strudel/blob/26cc7e2920e32ec01bf22e1dae8ced716462a158/packages/hydra/hydra.mjs#L50
window.P = (pattern: any) => {
return () => {
// parse using the strudel mini parser
const reified = window.strudel.mini.minify(pattern)

const now = window.strudel.core.getTime()

// query the current value
const arc = reified.queryArc(now, now)
return arc[0].value;
}
}

// initialized a streaming canvas with the strudel draw context canvas
// this allows us to use the strudel output
window.useStrudelCanvas = (s: any) => {
const canvas = window.strudel.draw.getDrawContext().canvas
canvas.style.display = "none"
s.init({src: canvas})
}

const clamp = (num: number, min: number, max: number) => Math.min(Math.max(num, min), max);


Expand Down
12 changes: 10 additions & 2 deletions packages/web/src/lib/strudel-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ export class StrudelWrapper {
protected _docPatterns: any;
protected _audioInitialized: boolean;
protected framer?: any;
protected mini?: any;
protected core?: any;
protected draw?: any;
protected webaudio?: any;

enableAutoAnalyze = false;
Expand Down Expand Up @@ -63,12 +66,17 @@ export class StrudelWrapper {
async importModules() {
// import desired modules and add them to the eval scope

this.mini = await import("@strudel/mini");
this.core = await import("@strudel/core");
this.draw = await import("@strudel/draw");

this.webaudio = await import("@strudel/webaudio");

await evalScope(
import("@strudel/core"),
this.core,
import("@strudel/midi"),
import("@strudel/mini"),
this.mini,
this.draw,
import("@strudel/tonal"),
import("@strudel/osc"),
import("@strudel/serial"),
Expand Down
Loading