Skip to content

Commit ce0c10e

Browse files
lukeweston1234Luke
andauthored
Feature/spec refactor (#50)
* hadamard * householder * version bump * api tweak * bump version * tweaks * version bump * typo * v bump * pull spec out and generate traits using Claude * wip doc gen * generate docs * starting docs * wip docs * shiki * more docs * wip docs * more docs * a bit half-assed, but some docs * more docs * sidebar * basic docs * version bump * redirect * vercel different sqlite adapter * fmt * wip docs * mobile layout * anchor fix * layout fix * bare bones meta * mobile tweaks --------- Co-authored-by: Luke <luke.weston@cyberus-technology.de>
1 parent e0f05bb commit ce0c10e

56 files changed

Lines changed: 5961 additions & 3450 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ target/
55
/samples
66
example.png
77
example.wav
8-
*.png
8+
/*.png
9+
/scripts/**/*.png
910
*.wav
1011
crates/legato-core/samples
1112
/result

crates/Cargo.lock

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/Cargo.toml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
[package]
22
name = "legato"
33
description = "Legato is a WIP audiograph and DSL for quickly developing audio applications"
4-
version = "0.0.25"
4+
version = "0.0.28"
55
edition = "2024"
66
repository="https://github.com/legato-dsp/legato"
77
license = "AGPL-3.0"
88

9+
[features]
10+
docs = ["dep:serde", "dep:serde_json"]
11+
912
[dependencies]
13+
serde = { version = "1", features = ["derive"], optional = true }
14+
serde_json = { version = "1", optional = true }
15+
1016
assert_no_alloc = "1.1.2"
1117
portable-atomic = { version = "1.11.1", features = ["float"] }
1218
arc-swap = "1.7.1"
@@ -27,6 +33,11 @@ rtrb = "0.3.3"
2733
[dev-dependencies]
2834
criterion = { version = "0.5", features = ["html_reports"] }
2935

36+
[[bin]]
37+
name = "export-docs"
38+
path = "src/bin/export_docs.rs"
39+
required-features = ["docs"]
40+
3041
[[bench]]
3142
name = "nodes"
3243
harness = false

crates/examples/delay.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use legato::{
44
builder::{LegatoBuilder, Unconfigured},
55
config::Config,
66
interface::AudioInterface,
7+
msg::ParamPayload,
78
ports::PortBuilder,
89
};
910

crates/examples/external.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ fn main() {
7979

8080
// Spawn prod consumer pair
8181

82-
let (producer, consumer) = rtrb::RingBuffer::new(4096 * 4); // 4 frames of headroom
83-
8482
let ports = PortBuilder::default().audio_out(2).build();
8583

84+
let (producer, consumer) = rtrb::RingBuffer::new(4096 * 4); // 4 frames of headroom
85+
8686
let (app, _) = LegatoBuilder::<Unconfigured>::new(config, ports)
8787
.register_audio_input("one", consumer, 1, config.block_size)
8888
.build_dsl(&graph);

crates/src/bin/export_docs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
#[cfg(feature = "docs")]
3+
println!("{}", legato::docs::export_nodes_json());
4+
}

crates/src/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ impl LegatoBuilder<Unconfigured> {
141141
let control_registry = control_registry_factory();
142142
let midi_registry = midi_registry_factory();
143143

144+
// Default namespaces
144145
namespaces.insert("audio".into(), audio_registry);
145146
namespaces.insert("control".into(), control_registry);
146147
namespaces.insert("midi".into(), midi_registry);

crates/src/docs.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use crate::{
2+
nodes::{
3+
audio::{
4+
adsr::Adsr,
5+
allpass::Allpass,
6+
delay::{DelayRead, DelayWrite},
7+
external::ExternalInput,
8+
hadamard::HadamardMixer,
9+
householder::HouseholderMixer,
10+
mixer::{MonoFanOut, TrackMixer},
11+
onepole::OnePole,
12+
ops::{AddDef, DivDef, GainDef, MultDef, SubDef},
13+
sampler::Sampler,
14+
sine::Sine,
15+
svf::Svf,
16+
sweep::Sweep,
17+
},
18+
control::{
19+
map::Map,
20+
phasor::{ClockDef, Phasor},
21+
sequencer::StepSequencer,
22+
signal::Signal,
23+
},
24+
midi::voice::{PolyVoice, Voice},
25+
},
26+
spec::{NodeDefinition, NodeDoc},
27+
};
28+
29+
pub fn audio_node_docs() -> Vec<NodeDoc> {
30+
vec![
31+
Sine::doc(),
32+
Sampler::doc(),
33+
DelayWrite::doc(),
34+
DelayRead::doc(),
35+
TrackMixer::doc(),
36+
MultDef::doc(),
37+
AddDef::doc(),
38+
SubDef::doc(),
39+
DivDef::doc(),
40+
GainDef::doc(),
41+
Adsr::doc(),
42+
Svf::doc(),
43+
MonoFanOut::doc(),
44+
Sweep::doc(),
45+
OnePole::doc(),
46+
Allpass::doc(),
47+
HadamardMixer::doc(),
48+
HouseholderMixer::doc(),
49+
ExternalInput::doc(),
50+
]
51+
}
52+
53+
pub fn control_node_docs() -> Vec<NodeDoc> {
54+
vec![
55+
Signal::doc(),
56+
Map::doc(),
57+
Phasor::doc(),
58+
ClockDef::doc(),
59+
StepSequencer::doc(),
60+
]
61+
}
62+
63+
pub fn midi_node_docs() -> Vec<NodeDoc> {
64+
vec![Voice::doc(), PolyVoice::doc()]
65+
}
66+
67+
/// Returns documentation for all built-in nodes across audio, control, and MIDI namespaces.
68+
pub fn all_node_docs() -> Vec<NodeDoc> {
69+
let mut docs = audio_node_docs();
70+
docs.extend(control_node_docs());
71+
docs.extend(midi_node_docs());
72+
docs
73+
}
74+
75+
/// Serialises all built-in node documentation to JSON
76+
#[cfg(feature = "docs")]
77+
pub fn export_nodes_json() -> String {
78+
serde_json::to_string_pretty(&all_node_docs()).expect("NodeDoc serialisation failed")
79+
}

crates/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ pub mod simd;
4141
pub mod spec;
4242
pub mod window;
4343

44+
#[cfg(feature = "docs")]
45+
pub mod docs;
4446
pub mod nodes;
4547

4648
#[derive(Debug, PartialEq, Clone)]

crates/src/nodes/audio/adsr.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,30 @@ impl Node for Adsr {
166166
&self.ports
167167
}
168168
}
169+
170+
use crate::{
171+
builder::{ResourceBuilderView, ValidationError},
172+
dsl::ir::DSLParams,
173+
node::DynNode,
174+
spec::NodeDefinition,
175+
};
176+
177+
impl NodeDefinition for Adsr {
178+
const NAME: &'static str = "adsr";
179+
const DESCRIPTION: &'static str = "Attack-decay-sustain-release envelope generator";
180+
const REQUIRED_PARAMS: &'static [&'static str] =
181+
&["attack", "decay", "sustain", "release", "chans"];
182+
const OPTIONAL_PARAMS: &'static [&'static str] = &[];
183+
184+
fn create(
185+
_rb: &mut ResourceBuilderView,
186+
p: &DSLParams,
187+
) -> Result<Box<dyn DynNode>, ValidationError> {
188+
let attack = p.get_f32("attack").expect("Must provide attack to ADSR");
189+
let decay = p.get_f32("decay").expect("Must provide decay to ADSR");
190+
let sustain = p.get_f32("sustain").expect("Must provide sustain to ADSR");
191+
let release = p.get_f32("release").expect("Must provide release to ADSR");
192+
let chans = p.get_usize("chans").expect("Must provide chans to ADSR");
193+
Ok(Box::new(Self::new(chans, attack, decay, sustain, release)))
194+
}
195+
}

0 commit comments

Comments
 (0)