Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions js/packages/core/lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ export function counter(a, b?) {
return createNode("counter", a, [resolve(b)]);
}

// Counter2 node
export function counter2(gate: ElemNode): NodeRepr_t;
export function counter2(props: OptionalKeyProps, gate: ElemNode): NodeRepr_t;
export function counter2(a, b?) {
if (typeof a === "number" || isNode(a)) {
return createNode("counter2", {}, [resolve(a)]);
}

return createNode("counter2", a, [resolve(b)]);
}

// Accum node
export function accum(xn: ElemNode, reset: ElemNode): NodeRepr_t;
export function accum(props: OptionalKeyProps, xn: ElemNode, reset: ElemNode): NodeRepr_t;
Expand Down
35 changes: 35 additions & 0 deletions js/packages/core/lib/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ export function geq(a, b, c?) {
return createNode("geq", a, [resolve(b), resolve(c)]);
}

// Alias comparison nodes
export const lt = le;
export const lte = leq;
export const gt = ge;
export const gte = geq;

export function pow(a: ElemNode, b: ElemNode): NodeRepr_t;
export function pow(props: OptionalKeyProps, a: ElemNode, b: ElemNode): NodeRepr_t;
export function pow(a, b, c?) {
Expand All @@ -213,6 +219,18 @@ export function eq(a, b, c?) {
return createNode("eq", a, [resolve(b), resolve(c)]);
}

export function neq(a: ElemNode, b: ElemNode): NodeRepr_t;
export function neq(props: OptionalKeyProps, a: ElemNode, b: ElemNode): NodeRepr_t;
export function neq(a, b, c?) {
// In a future update we'll collapse literal constants here; need to sort
// out how keys work in that case.
if (typeof a === "number" || isNode(a)) {
return sub(1, eq(a, b));
}

return sub(a, 1, eq(b, c));
}

export function and(a: ElemNode, b: ElemNode): NodeRepr_t;
export function and(props: OptionalKeyProps, a: ElemNode, b: ElemNode): NodeRepr_t;
export function and(a, b, c?) {
Expand Down Expand Up @@ -321,3 +339,20 @@ export function max(a, ...bs) {

return createNode("max", a, bs.map(resolve));
}

export function sign(x: ElemNode): NodeRepr_t;
export function sign(props: OptionalKeyProps, x: ElemNode): NodeRepr_t;
export function sign(a, b?) {
return (typeof a === "number" || isNode(a))
? createNode("sign", {}, [resolve(a)])
: createNode("sign", a, [resolve(b)]);
}

export function clamp(x: ElemNode, min: ElemNode, max: ElemNode): NodeRepr_t;
export function clamp(props: OptionalKeyProps, x: ElemNode, min: ElemNode, max: ElemNode): NodeRepr_t;
export function clamp(a, b, c, d?) {
if (typeof a === "number" || isNode(a)) {
return min(a, max(b, c));
}
return min(a, b, max(c, d));
}
18 changes: 18 additions & 0 deletions js/packages/core/lib/signals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,21 @@ export function select(g: ElemNode, a: ElemNode, b: ElemNode): NodeRepr_t {
export function hann(t: ElemNode): NodeRepr_t {
return el.mul(0.5, el.sub(1, el.cos(el.mul(2.0 * Math.PI, t))));
}

/**
* Converts a MIDI note number to a frequency in Hz.
*
* Middle C4 is MIDI note 60, which corresponds to 261.63 Hz.
*/
export function midi2frequency(midi: ElemNode): NodeRepr_t {
return el.mul(440, el.pow(2, el.div(el.sub(midi, 69), 12)));
}

/**
* Converts a frequency in Hz to a MIDI note number.
*
* Middle C4 is MIDI note 60, which corresponds to 261.63 Hz.
*/
export function frequency2midi(frequency: ElemNode): NodeRepr_t {
return el.add(69, el.mul(12, el.log2(el.div(frequency, 440))));
}
2 changes: 1 addition & 1 deletion js/packages/offline-renderer/elementary-wasm.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/packages/web-renderer/raw/elementary-wasm.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions runtime/elem/DefaultNodeTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ namespace elem
callback("sqrt", GenericNodeFactory<UnaryOperationNode<FloatType, std::sqrt>>());
callback("exp", GenericNodeFactory<UnaryOperationNode<FloatType, std::exp>>());
callback("abs", GenericNodeFactory<UnaryOperationNode<FloatType, std::abs>>());
callback("sign", GenericNodeFactory<UnaryOperationNode<FloatType, SignFunction>>());

// Binary math nodes
callback("le", GenericNodeFactory<BinaryOperationNode<FloatType, std::less<FloatType>>>());
Expand Down Expand Up @@ -94,6 +95,7 @@ namespace elem
callback("sparseq", GenericNodeFactory<SparSeqNode<FloatType>>());
callback("sparseq2", GenericNodeFactory<SparSeq2Node<FloatType>>());
callback("counter", GenericNodeFactory<CounterNode<FloatType>>());
callback("counter2", GenericNodeFactory<Counter2Node<FloatType>>());
callback("accum", GenericNodeFactory<AccumNode<FloatType>>());
callback("latch", GenericNodeFactory<LatchNode<FloatType>>());
callback("maxhold", GenericNodeFactory<MaxHold<FloatType>>());
Expand Down
43 changes: 43 additions & 0 deletions runtime/elem/builtins/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,49 @@ namespace elem
FloatType count = 0;
};

// Counts the number of rising edges until a reset signal is received
template <typename FloatType>
struct Counter2Node : public GraphNode<FloatType> {
using GraphNode<FloatType>::GraphNode;

void process (BlockContext<FloatType> const& ctx) override {
auto** inputData = ctx.inputData;
auto* outputData = ctx.outputData[0];
auto numChannels = ctx.numInputChannels;
auto numSamples = ctx.numSamples;

// If we don't have the inputs we need, we bail here and zero the buffer
// hoping to prevent unexpected signals.
if (numChannels < 2)
return (void) std::fill_n(outputData, numSamples, FloatType(0));

for (size_t i = 0; i < numSamples; ++i) {
auto const in = inputData[0][i];
auto const reset = inputData[1][i];

// When reset is high, reset counter
if ((FloatType(1.0) - reset) <= std::numeric_limits<FloatType>::epsilon()) {
count = FloatType(0);
}

// When the gate is high, count once
if ((FloatType(1.0) - in) <= std::numeric_limits<FloatType>::epsilon()) {
if (!risingEdge) {
count = count + FloatType(1);
risingEdge = true;
}
} else {
risingEdge = false;
}

outputData[i] = count;
}
}

FloatType count = 0;
bool risingEdge = false;
};

// Simply accumulates its input until reset
template <typename FloatType>
struct AccumNode : public GraphNode<FloatType> {
Expand Down
7 changes: 7 additions & 0 deletions runtime/elem/builtins/Math.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ namespace elem
std::atomic<int> channel = 0;
};

template <typename FloatType>
FloatType SignFunction(FloatType x) {
if (x == FloatType(0)) return FloatType(0);

return std::signbit(x) ? FloatType(-1.0) : FloatType(1.0);
}

template <typename FloatType>
struct Modulus {
FloatType operator() (FloatType x, FloatType y) {
Expand Down