Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
151 commits
Select commit Hold shift + click to select a range
9d81280
WIP: initial outlining
Aug 12, 2026
a923076
WIP: set up basic structure before implementing renderGraph
Aug 13, 2026
15b3089
Add design spec for native Renderer graph reconciliation
Aug 13, 2026
6253ab0
Add implementation plan for native Renderer graph reconciliation
Aug 13, 2026
a3becba
Ignore .worktrees directory used for isolated development worktrees
Aug 13, 2026
ab4a1ab
WIP: outline complete VERY UNSTABLE
Aug 15, 2026
3de55a6
remove superpowers docs (because we didnt use it)
Aug 15, 2026
3e54ba9
WIP: some refinements
Aug 16, 2026
2d81c17
WIP: improve audio graph semantics
Aug 17, 2026
333753f
move options into class
Aug 17, 2026
905783d
WIP: add a type alias for renderer
Aug 17, 2026
c8b06db
WIP: add type alias to Renderer
Aug 17, 2026
4b25c5f
WIP: remove type aliases
Aug 17, 2026
b0eb25c
prefer renderoptions outside of template
Aug 17, 2026
339f6c0
rename renderoptions
Aug 17, 2026
e359520
Add some missing headers in deps
Aug 18, 2026
8f29329
WIP: convert to c++17 syntax
Aug 18, 2026
fd920fd
WIP: remove c++23 language standard
Aug 18, 2026
4e1170c
target cxx17
Aug 18, 2026
2467983
WIP: get rid of contains call
Aug 18, 2026
3989885
WIP: more fixes
Aug 18, 2026
74cd917
WIP: use c++17 syntax and fix js::Array building
Aug 18, 2026
7b2f450
make instructions batching more efficient
Aug 18, 2026
6f58d73
implement array equality and add some small syntax improvements
Aug 18, 2026
8daefd7
WIP: more small improvements and comments
Aug 18, 2026
5f31886
improve comments on Value equality
Aug 18, 2026
fdb96be
comments and tidying up renderer.h
Aug 18, 2026
ac8f52d
get rid of unused constructors
Aug 18, 2026
3b55788
improve Value type semantics and add constructors back
Aug 18, 2026
502e6ac
clean up SymbolicGraph.h
Aug 18, 2026
be48d83
Clean up renderer
Aug 18, 2026
f5bb44a
Clean up HashUtils.h
Aug 18, 2026
ae38ebb
add back space
Aug 18, 2026
1c6dc3a
dont use the copy constructor
Aug 18, 2026
fa3859c
try to push_back instaed of braced init list
Aug 18, 2026
8e9f819
WIP: Set up googletest for testing native renderer
Aug 19, 2026
820bbb7
WIP: set up snapshot style testing
Aug 19, 2026
8dd3e93
WIP: add some comments about adding statistics
Aug 19, 2026
d5b0caf
add statistics to renderGraph
Aug 19, 2026
6ff8026
WIP: outline the cycle node
Aug 20, 2026
96d8142
add readme for native renderer tests
Aug 20, 2026
2ae407c
Add a couple more node types to lib
Aug 20, 2026
e2d1fee
Basic Sine Wave Test complete
Aug 20, 2026
37e9b6f
better move and forwarding
Aug 20, 2026
230de40
WIP: rename resolveXs to resolve
Aug 20, 2026
6cc1f2a
Add comments
Aug 20, 2026
676d6fb
WIP: add some comments
Aug 21, 2026
5efab93
implement unpack for multichannel nodes
Aug 21, 2026
888d1cf
WIP: outline how the createRef function will work
Aug 22, 2026
6d969dc
get rid of runtimeinterface and add findNode method
Aug 26, 2026
0ce56b6
use mRuntime->findNode in mount instead of duplicated nodeMap
Aug 26, 2026
7a7f7f9
implement createRef
Aug 26, 2026
118c37b
improve activate roots behavior
Aug 26, 2026
5a3c858
make test compile
Aug 26, 2026
9261f48
add numeric literal resolution test
Aug 26, 2026
2bca79c
add mermaid sequence diagram output to graph snapshots
Aug 26, 2026
185057c
fix discrepancy between sine examples
Aug 26, 2026
123cc56
WIP: complete the simple core helpers
Aug 27, 2026
d2609ef
add rvalue overloads for Value containers and add NumberArray and imp…
Aug 27, 2026
57a7cda
WIP: complete Core lib
Aug 28, 2026
8ab2478
move props stuff to props.h and introduce Required type
Aug 28, 2026
d9d1a18
add comment to resolve function
Aug 28, 2026
4c2eba3
move some required props to the props object
Aug 28, 2026
e193cae
complete Core.h
Aug 28, 2026
920cd50
complete math lib
Aug 28, 2026
c3e9df6
complete AI pass of lib nodes
Aug 28, 2026
908d282
Add design spec for porting core/mc/lib/hashing JS tests to NativeRen…
Aug 28, 2026
1967b3e
Add implementation plan for porting core/mc/hashing JS tests to Nativ…
Aug 28, 2026
5505e5b
Mix child outputChannel into node hash, matching NodeRepr.res
Aug 28, 2026
c9e6316
Fix appendChild to use child's outputChannel; fix NodeRef setter's re…
Aug 28, 2026
d4016d2
Port core.test.js 'distinguish by props' to NativeRendererTests
Aug 28, 2026
64f608d
Port core.test.js 'multi-channel basics' to NativeRendererTests
Aug 28, 2026
e72b872
Port core.test.js 'simple sharing' to NativeRendererTests
Aug 28, 2026
667d3aa
Port core.test.js 'distinguished subtrees by key' to NativeRendererTests
Aug 28, 2026
0c0ad33
Port core.test.js 'structural equality with value change' to NativeRe…
Aug 29, 2026
938c9f3
Port core.test.js 'switch and switch back' to NativeRendererTests
Aug 29, 2026
2a347b3
Port core.test.js 'refs' to NativeRendererTests
Aug 29, 2026
f886284
Port mc.test.js 'hashing reflects outputChannel from child nodes' to …
Aug 29, 2026
7017728
Port hashing.test.js graphs to NativeRendererTests
Aug 29, 2026
ff728e0
Fix findings from final native-renderer branch review
Aug 29, 2026
4aba175
add return code and improve comment
Aug 29, 2026
01c70ce
remove NumberArray
Aug 29, 2026
508fcd3
consolidate tests to NativeRendererTests
Aug 29, 2026
aa8f682
Merge pull request #4 from parkernilson/parkernilson/native-renderer-…
parkernilson Aug 29, 2026
c4d2765
convert to file relative include paths
Aug 29, 2026
b7aa70d
fix readme
Aug 29, 2026
9ffc9de
Run NativeRendererTests in CI alongside other native builds
Aug 29, 2026
eccce07
Merge branch 'parkernilson/native-renderer' into parkernilson/native-…
Aug 29, 2026
bec69d5
fix weird rounding issues that caused flaky test results
Aug 29, 2026
79267f6
Add design doc for native renderer CLI proof-of-concept
Aug 29, 2026
75eeb82
Scaffold cli-native project with native HelloSine graph builder
Aug 29, 2026
84f1d1d
Add elemcli-native realtime playback binary
Aug 29, 2026
57b43f3
Add elembench-native benchmark binary
Aug 29, 2026
5f7fafb
Check renderGraph result before running native cli/benchmark
Aug 29, 2026
6f90788
Explain vendored miniaudio.h and drop satisfied Renderer.h TODO
Aug 29, 2026
100caf0
Add cli-native README
Aug 29, 2026
a595897
Add implementation plan for native-renderer CLI PoC
Aug 29, 2026
5683cfa
make variables const
Aug 29, 2026
6045ce6
add logging for madevice failure and bump elemaudio package version
Aug 29, 2026
71cc74d
fix miniaudio logging for cli native
Aug 29, 2026
546260b
remove mentions to what generator you should use in readmes and use s…
Aug 29, 2026
b1f73e5
Add design doc for NativeRendererTests TODO coverage
Aug 29, 2026
e8ce7d2
Add implementation plan for NativeRendererTests TODO coverage
Aug 29, 2026
a1bfc45
Add ChangingLeafPropRecreatesWholeTree native renderer test
Aug 29, 2026
57bbfcc
Add ChangingMiddleNodeRedrawsOnlyParents native renderer test
Aug 29, 2026
d0f1966
Add AddingMiddleNodeRedrawsOnlyParents native renderer test
Aug 29, 2026
0e9eddf
Add GcCleansUpUnusedNodes native renderer test
Aug 29, 2026
8983aa7
Consolidate custom node TODOs in NativeRendererTests
Aug 29, 2026
1c8d939
Address final-review polish: reorder trailing TODO, clarify gc test c…
Aug 29, 2026
33ebf70
fix comment about native tests
Aug 29, 2026
850446a
remove edits to cli/README.md
Aug 29, 2026
0401245
remove edit to readme
Aug 29, 2026
9fe826f
again remove edit to readme
Aug 29, 2026
451ebb0
get rid of native benchmark and modify readmes
Aug 31, 2026
b3b4732
WIP: outline the renderer benchmark scenario
Aug 31, 2026
d05d11e
WIP: convert from class inheritance to lambdas and factories
Sep 1, 2026
5feccc8
hook up renderer benchmarks to cli
Sep 1, 2026
8df24ef
WIP: add constants for function names
Sep 1, 2026
1f6f60c
WIP: create js renderer benchmark
Sep 1, 2026
0371542
rename a bunch of things
Sep 1, 2026
492eddd
add a benchmarking section to the cli readme
Sep 1, 2026
0adf8e2
pass shared pointers by const ref
Sep 1, 2026
6adce09
Remove templating for Renderer benchmarks because it doesnt actually …
Sep 1, 2026
6850acb
remove some stuff from readme
Sep 1, 2026
b156974
use performance.now
Sep 1, 2026
982b280
Add design doc for cli-native usage/--list/graph registry
Sep 1, 2026
ac6f659
rename benchmark
Sep 1, 2026
f42e637
add arguments to cli native
Sep 1, 2026
8a5a3db
specify debug
Sep 1, 2026
aba9a8b
include file and scenario name in benchmark output
Sep 1, 2026
7015a02
add and remove a comment
Sep 1, 2026
926d77a
use better arg parsing
Sep 1, 2026
5fe7e00
remove a todo
Sep 1, 2026
70cc355
remove a TODO
Sep 1, 2026
6cc661d
remove Release default
Sep 1, 2026
d40e0f2
remove superpowers specs and docs
Sep 1, 2026
70b93f6
remove includes in deps
Sep 1, 2026
0f0744d
add back streambuf include
Sep 1, 2026
58f8cf0
upgrade json.hpp dep
Sep 1, 2026
6788907
Revert "upgrade json.hpp dep"
Sep 1, 2026
b5e7db5
Revert "add back streambuf include"
Sep 1, 2026
f341e7a
improve comments
Sep 1, 2026
934d288
Merge remote-tracking branch 'refs/remotes/origin/parkernilson/native…
Sep 1, 2026
36f619f
remove include
Sep 1, 2026
2b327f4
Merge remote-tracking branch 'refs/remotes/origin/parkernilson/native…
Sep 1, 2026
b50f8dd
remove unused constructor for value
Sep 2, 2026
8f676fc
Rename SymbolicGraph to NodeRepr
Sep 2, 2026
012a860
return sptr
Sep 3, 2026
585103a
add same notes about other languages that I added to the website
Sep 3, 2026
3a70e46
add preprocessor fix for msvc variadic macro bug
Sep 3, 2026
6c35283
convert to c++17 syntax
Sep 3, 2026
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 .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ jobs:
cmake --build . --config Release -j 8
popd

- name: Test
shell: bash
run: |
set -x
set -e

# Run the native tests
pushd ./build/native/
ctest -C Release --output-on-failure
popd

wasm:
runs-on: ubuntu-latest
steps:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
build
dist
node_modules
.worktrees

.merlin
.cljs_node_repl
.cpcache
.cache
.DS_Store
.idea

*.swp

Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
[submodule "runtime/elem/third-party/signalsmith-stretch"]
path = runtime/elem/third-party/signalsmith-stretch
url = https://github.com/Signalsmith-Audio/signalsmith-stretch.git
[submodule "tests/third-party/googletest"]
path = tests/third-party/googletest
url = https://github.com/google/googletest.git
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
cmake_minimum_required(VERSION 3.15)
project(elementary VERSION 0.11.5)


option(ONLY_BUILD_WASM "Only build the wasm subdirectory" OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)

if(MSVC)
# MSVC's default (non-conformant) preprocessor mishandles __VA_ARGS__
# expansion in nested macros, which breaks the ELEM_ARG_COUNT/DEFINE_PROPS_STRUCT
# macros in runtime/elem/lib/Props.h. The conformant preprocessor fixes this.
add_compile_options(/Zc:preprocessor)
endif()

if(${ONLY_BUILD_WASM})
add_subdirectory(runtime)
add_subdirectory(wasm)
else()
enable_testing()
add_subdirectory(runtime)
add_subdirectory(cli)
add_subdirectory(cli-native)
add_subdirectory(tests)
endif()
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
* **Dynamic:** Most audio processing frameworks and tools facilitate building static processes. But what happens as your audio requirements change throughout the user journey? Elementary is designed to facilitate and adapt to the dynamic nature of modern audio applications.
* **Portable:** By decoupling the JavaScript API from the underlying audio engine (the "what" from the "how"), Elementary enables writing portable applications. Whether the underlying engine is running in the browser, an audio plugin, or an embedded device, your JavaScript layer remains the same.

Elementary also has community supported bindings for languages other than JavaScript in [Other Languages](https://www.elementary.audio/docs/other_languages/community-supported-language-bindings).

## Getting Started

Every Elementary application starts with the [@elemaudio/core](https://www.elementary.audio/docs/packages/core) package ([npm](https://www.npmjs.com/package/@elemaudio/core), [source](./js/packages/core)), which provides the
Expand All @@ -27,6 +29,7 @@ If you're new to the project, we recommend studying the following workflows to g

* Use the [@elemaudio/web-renderer](https://www.elementary.audio/docs/packages/web-renderer) package ([npm](https://www.npmjs.com/package/@elemaudio/web-renderer), [source](./js/packages/web-renderer)) with your favorite frontend UI library to make an audio web application
* Use the [@elemaudio/offline-renderer](https://www.elementary.audio/docs/packages/offline-renderer) package ([npm](https://www.npmjs.com/package/@elemaudio/offline-renderer), [source](./js/packages/offline-renderer)) with Node.js for static file processing
* Use the [elementary-swift](https://github.com/parkernilson/elementary-swift) package to develop an iOS or macOS application

Once you're ready to dive in, we suggest starting with one of these ideas:

Expand Down
33 changes: 33 additions & 0 deletions cli-native/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.15)
project(cli-native VERSION 0.11.0)

add_library(elemcli_native_graph STATIC
graphs/HelloSine.cpp
graphs/GraphRegistry.cpp)

target_include_directories(elemcli_native_graph PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/miniaudio)

target_compile_features(elemcli_native_graph PUBLIC
cxx_std_17)

target_link_libraries(elemcli_native_graph PUBLIC
elem::runtime)

if(MSVC)
target_compile_options(elemcli_native_graph PRIVATE /W4)
else()
target_compile_options(elemcli_native_graph PRIVATE -Wall -Wextra)
endif()

add_executable(elemcli-native RealtimeMain.cpp)

target_link_libraries(elemcli-native PRIVATE elemcli_native_graph)

if(UNIX AND NOT APPLE)
find_package(Threads REQUIRED)
target_link_libraries(elemcli-native PRIVATE
Threads::Threads
${CMAKE_DL_LIBS})
endif()
30 changes: 30 additions & 0 deletions cli-native/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# cli-native

This version of the cli uses the native renderer instead of the js based renderer to render the Audio Graph.

The cli tool here is not meant to be a fully featured, end-user product, but rather
a concise demonstration of using Elementary's native renderer with the native engine.

## Building

```bash
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build --target elemcli-native
```

## Running

- `./build/elemcli-native --list` lists the available graphs.
- `./build/elemcli-native --graph <name>` plays the named graph to the
default audio device. Press Enter to exit.
- `./build/elemcli-native --help` prints usage information.

## Adding a graph

1. Add `graphs/MyGraph.h`/`.cpp` exposing a `buildMyGraph()` function that
returns a `std::vector<std::shared_ptr<elem::SymbolicGraphNode>>` (see
`graphs/HelloSine.h`/`.cpp` for an example).
2. Register it by adding an entry to the vector in
`graphs/GraphRegistry.cpp`.
3. Add `graphs/MyGraph.cpp` to the `elemcli_native_graph` sources in
`CMakeLists.txt`.
176 changes: 176 additions & 0 deletions cli-native/RealtimeMain.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
#include <algorithm>
#include <array>
#include <iostream>
#include <memory>
#include <vector>

#include "graphs/GraphRegistry.h"
#include "elem/Renderer.h"
#include "elem/Runtime.h"

#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"


// A simple struct to proxy between the audio device and the Elementary engine
struct DeviceProxy {
DeviceProxy(double sampleRate, size_t blockSize)
: scratchData(2 * blockSize), runtime(std::make_shared<elem::Runtime<float>>(sampleRate, blockSize))
{}

void process(float* outputData, size_t numChannels, size_t numFrames)
{
// We might hit this the first time around, but after that should be fine
if (scratchData.size() < (numChannels * numFrames))
scratchData.resize(numChannels * numFrames);

auto* deinterleaved = scratchData.data();
std::array<float*, 2> ptrs {deinterleaved, deinterleaved + numFrames};

runtime->process(
nullptr,
0,
ptrs.data(),
numChannels,
numFrames,
nullptr
);

for (size_t i = 0; i < numChannels; ++i)
{
for (size_t j = 0; j < numFrames; ++j)
{
outputData[i + numChannels * j] = deinterleaved[i * numFrames + j];
}
}
}

std::vector<float> scratchData;
std::shared_ptr<elem::Runtime<float>> runtime;
};

void audioCallback(ma_device* pDevice, void* pOutput, const void* /* pInput */, ma_uint32 frameCount)
{
auto* proxy = static_cast<DeviceProxy*>(pDevice->pUserData);

const auto numChannels = static_cast<size_t>(pDevice->playback.channels);
const auto numFrames = static_cast<size_t>(frameCount);

proxy->process(static_cast<float*>(pOutput), numChannels, numFrames);
}

void printUsage(const char* programName)
{
std::cout << "Usage: " << programName << " --graph <name>" << std::endl;
std::cout << std::endl;
std::cout << "Renders an Elementary audio graph to the default audio device." << std::endl;
std::cout << std::endl;
std::cout << "Options:" << std::endl;
std::cout << " --graph <name> Render the named graph" << std::endl;
std::cout << " --list List the available graphs" << std::endl;
std::cout << " --help, -h Show this usage information" << std::endl;
std::cout << std::endl;
std::cout << "Example:" << std::endl;
std::cout << " " << programName << " --graph hello-sine" << std::endl;
}

void printGraphList()
{
for (auto const& graphInfo : elem::lib::getGraphRegistry()) {
std::cout << graphInfo.name << " — " << graphInfo.description << std::endl;
}
}

int main(int argc, char** argv)
{
std::string graphName;
std::vector<std::string> args(argv + 1, argv + argc);

for (size_t i = 0; i < args.size(); ++i) {
if (args[i] == "--help" || args[i] == "-h") {
printUsage(argv[0]);
return 0;
} else if (args[i] == "--list") {
printGraphList();
return 0;
} else if (args[i] == "--graph") {
if (i + 1 >= args.size()) {
std::cerr << "Error: --graph requires a graph name" << std::endl;
printUsage(argv[0]);
return 1;
}

graphName = args[++i];
}
}

if (graphName.empty()) {
printUsage(argv[0]);
return 1;
}

auto const& registry = elem::lib::getGraphRegistry();
auto it = std::find_if(registry.begin(), registry.end(), [&graphName](elem::lib::GraphInfo const& graphInfo) {
return graphInfo.name == graphName;
});

if (it == registry.end()) {
std::cerr << "Error: unknown graph \"" << graphName << "\". Available graphs:" << std::endl;
printGraphList();
return 1;
}

ma_result result;

ma_device_config deviceConfig;
ma_device device;

// XXX: I don't see a way to ask miniaudio for a specific block size. Let's just allocate
// here for 1024 and resize in the first callback if we need to.
std::unique_ptr<DeviceProxy> proxy = std::make_unique<DeviceProxy>(44100.0, 1024);

deviceConfig = ma_device_config_init(ma_device_type_playback);

deviceConfig.playback.pDeviceID = nullptr;
deviceConfig.playback.format = ma_format_f32;
deviceConfig.playback.channels = 2;
deviceConfig.sampleRate = 44100;
deviceConfig.dataCallback = audioCallback;
deviceConfig.pUserData = proxy.get();

result = ma_device_init(nullptr, &deviceConfig, &device);

if (result != MA_SUCCESS) {
std::cout << "Failed to start the audio device! Exiting..." << std::endl;
return 1;
}

// Build and render the graph before audio starts
elem::Renderer<float> renderer(proxy->runtime);
auto stats = renderer.renderGraph(it->build());

std::cout << "Render result: " << stats.result << std::endl;
std::cout << "Nodes added: " << stats.nodesAdded << std::endl;
std::cout << "Edges added: " << stats.edgesAdded << std::endl;
std::cout << "Props written: " << stats.propsWritten << std::endl;

if (stats.result != elem::ReturnCode::Ok()) {
std::cerr << "Failed to render graph: " << elem::ReturnCode::describe(stats.result) << std::endl;
ma_device_uninit(&device);
return 1;
}

result = ma_device_start(&device);

if (result != MA_SUCCESS) {
std::cout << "Failed to start the audio device! Exiting..." << std::endl;
ma_device_uninit(&device);
return 1;
}

std::cout << "Press Enter to exit..." << std::endl;
getchar();

ma_device_uninit(&device);
return 0;
}
13 changes: 13 additions & 0 deletions cli-native/graphs/GraphRegistry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "GraphRegistry.h"

#include "HelloSine.h"

namespace elem::lib {
std::vector<GraphInfo> const& getGraphRegistry() {
static const std::vector<GraphInfo> registry = {
{"hello-sine", "A single 440Hz sine tone at 0.3 gain", buildHelloSineGraph},
};

return registry;
}
}
18 changes: 18 additions & 0 deletions cli-native/graphs/GraphRegistry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include <functional>
#include <memory>
#include <string>
#include <vector>

#include "elem/NodeRepr.h"

namespace elem::lib {
struct GraphInfo {
std::string name;
std::string description;
std::function<std::vector<std::shared_ptr<elem::NodeRepr>>()> build;
};

std::vector<GraphInfo> const& getGraphRegistry();
}
13 changes: 13 additions & 0 deletions cli-native/graphs/HelloSine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "HelloSine.h"

#include "elem/lib/Math.h"
#include "elem/lib/Oscillators.h"

namespace elem::lib {
std::vector<std::shared_ptr<elem::NodeRepr>> buildHelloSineGraph() {
return {
mul({0.3, cycle(440.0)}),
mul({0.3, cycle(440.0)}),
};
}
}
10 changes: 10 additions & 0 deletions cli-native/graphs/HelloSine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <memory>
#include <vector>

#include "elem/NodeRepr.h"

namespace elem::lib {
std::vector<std::shared_ptr<elem::NodeRepr>> buildHelloSineGraph();
}
Loading