el.phasorare primitive nodes, which means that after Elementary has completed the render, the realtime engine will be operating with the same idea of an
el.subnode and an
core.renderare identical to the ones passed in the prior example, because invoking our
440yields the same structure. This way of abstraction over primitive nodes works well, and is a pattern you can use freely when building applications in Elementary. But there's another way of accomplishing a similar feat which allows Elementary an opportunity to sneak in some helpful rendering tactics.
sawfunction to make what I call a supersaw: a big mess of detuned sawtooth oscillators all playing at once (an awesome starting point for subtractive synthesis):
core.rendersees a structure which has already completely decayed to primitive nodes. This time, our node structure is significantly bigger than the former example. Let's add a little more here to filter our supersaw with an imaginary user-controlled cutoff frequency:
keyprop, but here it helps our example). Notice, though, before
core.render()even sees this new structure, we've already evaluated
supersawand built that whole substructure. Elementary in turn will traverse this whole substructure before ultimately recognizing that our supersaw hasn't changed, which feels like a bunch of wasted effort! Here we can make this both faster and simpler by introducing a new type of node: the composite node. Let's make a few small changes to our
supersawfunction now takes a
propsargument, and second, our
supersawis wrapped in
el.createNodeFactory. With this, when we actually then invoke the
supersawfunction, we receive a new Node which has not yet decayed to any primitives, it's simply a Node which Elementary understands must still be resolved before it can complete its render. This is a step that happens inside of
core.renderfor any unresolved composite nodes, and this is also an opportunity to help Elementary operate quickly: composite nodes offer a memoization step, which allows Elementary to leave composite nodes unresolved during the render process when it realizes ahead of time that the structure described by the composite node will not change in this render pass. Let's revisit our filter:
core.rendera small structure with an unresolved
supersawcomposite node, and on all but the first render we can tell Elementary not to bother resolving it again. This way, the amount of work to do inside of
core.renderis significantly limited, at the benefit of your application's speed.
el.createNodeFactoryintroduces the idea of
propsto your own graph nodes, which can be a helpful way for structuring your application and passing relevant state throughout your signal graph.