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

Fallback Limiter in Playground #4

Open
nick-thompson opened this issue Jan 7, 2024 · 8 comments · May be fixed by #11
Open

Fallback Limiter in Playground #4

nick-thompson opened this issue Jan 7, 2024 · 8 comments · May be fixed by #11

Comments

@nick-thompson
Copy link
Collaborator

Add a default limiter to the Playground which ideally stays out of the way but which would clamp anything going over 0dB. Mostly as a safety/panic mechanism to catch unexpected loud noises while the user is working

@mark-mxwl
Copy link
Contributor

Hi @nick-thompson! Happy to help with this one. Are you intending for the limiter to be applied to the runtime, or as an addition to the editor's default constant?

@nick-thompson
Copy link
Collaborator Author

Awesome, thanks @mark-mxwl! I was imagining it would go right here: https://github.com/elemaudio/website/blob/main/src/components/playground/runtime.js#L46-L49. Basically whatever the user exports from their playground module, we evaluate it and then pass the results through some el.limit() style function. The gotcha is that there is no el.limit in the elementary standard library so this task will include writing a limiter or using the existing el.compress with a suitable ratio. How's that sound?

@mark-mxwl
Copy link
Contributor

Sounds good @nick-thompson! I think dialing in el.compress as a limiter would work just fine (though a dedicated limiter module would be really cool to have at some point). I'll have a PR up sometime this weekend. 🙌

@nick-thompson
Copy link
Collaborator Author

Great, thanks!

@mark-mxwl
Copy link
Contributor

mark-mxwl commented Apr 28, 2024

Hey @nick-thompson! I was hoping to make this one easy on you and just knock it out. However, I'm running into an issue. I'm still new to your library, so I may be overlooking the obvious, but here's where I'm at. Looking at el.compress, it accepts an ElemNode for the sidechain and xn parameters. From what I can gather, userOutput returns an object of the type ElemNode, which represents an audio signal within the context of this library. However, when userOutput is passed to the compressor, it throws the following error:

Invariant Violation: Whoops, expecting a Node type here! Got: object
    at invariant (webpack-internal:///./node_modules/invariant/browser.js:38:15)
    at resolve (webpack-internal:///./node_modules/@elemaudio/core/dist/index.js:1121:3)
    at Object.env (webpack-internal:///./node_modules/@elemaudio/core/dist/index.js:1259:59)
    at Object.compress (webpack-internal:///./node_modules/@elemaudio/core/dist/index.js:1572:20)
    at Runtime.runUserCode (webpack-internal:///./src/components/playground/runtime.js:41:74)
    at async eval (webpack-internal:///./src/components/playground/index.js:99:19)

While the Playground editor itself accepts ElemNode as valid input for el.compress, the behavior is different in the runtime--even when userOutput is an identical obj.

Any guidance you could offer would be greatly appreciated!

@nick-thompson
Copy link
Collaborator Author

Hey @mark-mxwl, mind sharing the code you wrote? Without looking at it, my only guess is this: userOutput there is intended to support either an array of output signals (for stereo or multi-channel rendering), or a single output signal (for mono rendering). If you get an array you'll have to unpack it and apply the limiter to both channels:

      const limit = (xn) => el.compress(10, 100, -48, 4, xn, xn);
      const userOutput = render();
      const stats = Array.isArray(userOutput)
        ? await this.core.render(...userOutput.map(limit))
        : await this.core.render(limit(userOutput), limit(userOutput));

Something like that, with more sensible parameters for the atk/rel/thresh/ratio.

The error you're seeing there just suggests that one of the arguments you've passed to el.compress (likely the sidechain argument because we see el.env in the callstack) is not of type ElemNode, so it's not valid type for the graph construction. It might be helpful to drop a debugger or a console log there to inspect the type before you pass it in.

@mark-mxwl
Copy link
Contributor

mark-mxwl commented Apr 30, 2024

@nick-thompson, really appreciate the help! Funny, but the code I had was nearly identical, just with the limiter dialed in as so:

      const userOutput = render();
      const limit = (n) => el.compress(1, 10, -3, 20, n, n);
      const stats = Array.isArray(userOutput)
        ? await this.core.render(...userOutput.map(limit))
        : await this.core.render(limit(userOutput), limit(userOutput));

If you log the user output from both the Playground UI and runtime.js, you return the same ElemNode object. But running an isNode check inside the Playground returns true for type NodeRepr_t, and false in the runtime. See below:

True when logging from Playground; false when logging from runtime.js:

Object { symbol: "__ELEM_NODE__", hash: 520300429, kind: "sin", props: {}, children: {…} }
children: Object { hd: {…}, tl: 0 }
hash: 520300429
kind: "sin"
props: Object {  }
symbol: "__ELEM_NODE__"
<prototype>: Object { … }

@mark-mxwl
Copy link
Contributor

Ah, I got it. Just updated @elemaudio/core and @elemaudio/web-renderer to 3.2.x. The problem was the isNode function itself: In the lib. version I was using, isNode was checking for a .TAG value of 4 for symbol, when userOutput.symbol is, of course, a string. The isNode func. in the updated library reflects this with a .TAG value of 1, for string. 🙌

I'll get a PR up in a bit.

@mark-mxwl mark-mxwl linked a pull request Apr 30, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants