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

New Bus system to replace naive Arc<Mutex<Buffer>> System #58

Merged
merged 32 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2bdd62c
Add new channels and example "test" plugin (temp)
exa04 Nov 4, 2024
b8d1c05
Remove old `Arc<Mutex>`'d peak buffer from test
exa04 Nov 4, 2024
761b92e
Add `enqueue_latest` to visualizer buffer
exa04 Nov 5, 2024
0144bae
WIP
exa04 Nov 5, 2024
6985aab
Allow MPMC scenarios via `blinkcast`
exa04 Nov 7, 2024
efecb0c
Add oscilloscope to new example
exa04 Nov 8, 2024
47773e3
Implement new system for RMS buffer
exa04 Nov 11, 2024
7049973
Temporarily remove lots of stuff
exa04 Dec 15, 2024
2f296ed
Start work on "accumulators" system
exa04 Dec 15, 2024
c0c464b
Accumulators progress
exa04 Dec 17, 2024
0e2789c
Re-add meter
exa04 Dec 17, 2024
77bc328
Move inline macros to impl
exa04 Dec 17, 2024
56d5440
Re-add oscilloscope
exa04 Dec 18, 2024
2fad50f
Re-add histogram
exa04 Dec 21, 2024
e7c50ab
Add new benchmark
exa04 Dec 21, 2024
b3587b1
WIP bus
exa04 Jan 4, 2025
011df7d
Add dispatchers for Graph, Meter and Oscilloscope
exa04 Jan 4, 2025
cf7953a
Fix meter size issue
exa04 Jan 4, 2025
84801ff
Implement histogram
exa04 Jan 4, 2025
6ca9884
Add lissajous
exa04 Jan 5, 2025
6aca503
Re-introduce peak graph example
exa04 Jan 5, 2025
48c244d
Rename benchmark
exa04 Jan 6, 2025
715b414
Update oscilloscope on draw
exa04 Jan 7, 2025
6777182
Make visualizers take in an Arc<Bus> directly
exa04 Jan 14, 2025
7421974
Add `subscribe` function to busses
exa04 Jan 14, 2025
b8217f6
Remove `is_empty`
exa04 Jan 14, 2025
7bb836c
Documentation and some re-structuring
exa04 Jan 14, 2025
4e39067
fmt
exa04 Jan 14, 2025
086a067
Update readme
exa04 Jan 16, 2025
7637729
Update screenshots
exa04 Jan 16, 2025
0dacf03
Add spectrum to visualizers example
exa04 Jan 16, 2025
5b34978
Update README.md
exa04 Jan 16, 2025
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
1,627 changes: 1,035 additions & 592 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ description = "Composable views and associated data structures for nih-plug UIs
resolver = "2"
members = [
"xtask",
"examples/visualizers", "examples/peak_graph", "examples/histogram",
"examples/visualizers",
"examples/peak_graph",
"examples/benchmark_lots_of_visualizers"
]

[lib]
Expand All @@ -20,6 +22,12 @@ nih_plug = { git = "https://github.com/robbert-vdh/nih-plug.git" }
lazy_static = "1.4.0"
realfft = "3.3.0"
triple_buffer = "7.0.0"
crossbeam-channel = "0.5.13"
crossbeam-queue = "0.3.11"
arc-swap = "1.7.1"
atomic_bitfield = "0.1.0"
blinkcast = "0.2.0"
atomic-bus = "0.1.0"

[dev-dependencies]
rand = "0.8.5"
175 changes: 116 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ plug-in user interfaces with ease. It uses various custom data structures for
real-time visualizers, allowing you to easily build beautiful, performant
plug-in UIs.

Here's a demo ([YouTube mirror](https://www.youtube.com/watch?v=DQ-9XRBLpB4))
Here's a demo ([YouTube mirror](https://www.youtube.com/watch?v=He70jwvdjFU))

https://github.com/223230/cyma/assets/68156346/dea8ee3e-7162-4752-a569-6dc4218b0745
https://github.com/user-attachments/assets/456a6705-5936-4118-a527-fb8999a91041

Wanna see the code behind this? It's [this example!](./examples/visualizers)

Expand Down Expand Up @@ -58,80 +58,137 @@ feature request so it can be added!

## ❓ Example

Here's how to create a basic oscilloscope with a grid background.
Here's how to create a basic oscilloscope.

![Oscilloscope](doc/example.png)

Visualizers communicate with your plugin via busses. One bus can feed multiple
visualizers. Just add it to your plugin like so:

```rust
Oscilloscope::new(
cx,
Data::oscilloscope_buffer,
(-1.2, 1.2),
ValueScaling::Linear,
)
.background_color(Color::rgba(120, 120, 120));
pub struct OscopePlugin {
params: Arc<OscopeParams>,
bus: Arc<MonoBus>,
}

impl Plugin for OscopePlugin {
fn initialize(
&mut self,
_: &AudioIOLayout,
buffer_config: &BufferConfig,
_: &mut impl InitContext<Self>,
) -> bool {
self.bus.set_sample_rate(buffer_config.sample_rate);
true
}

fn process(
&mut self,
buffer: &mut Buffer,
_: &mut AuxiliaryBuffers,
_: &mut impl ProcessContext<Self>,
) -> ProcessStatus {
if self.params.editor_state.is_open() {
self.bus.send_buffer_summing(buffer);
}
ProcessStatus::Normal
}

fn editor(&mut self, _async_executor: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
editor::create(
self.bus.clone(),
self.params.editor_state.clone(),
)
}

...
}
```

Here, `Data::oscilloscope_buffer` is an `Arc<Mutex<WaveformBuffer>>`, a buffer
that allows for your audio to be sent to the `Oscilloscope` in a much smaller
package, while retaining peak information. Here, it's configured to be 512
samples long, and it represents 10 seconds of audio at 44.1 kHz.
Now, in your editor code, you just need to subscribe to the bus. Then, you can
use it for visualizers like this oscilloscope:

```rust
pub fn create(
bus: Arc<MonoBus>,
editor_state: Arc<ViziaState>,
) -> Option<Box<dyn Editor>> {
create_vizia_editor(editor_state, ViziaTheming::default(), move |cx, _| {
bus.subscribe(cx);
Oscilloscope::new(cx, bus.clone(), 4.0, (-1.0, 1.0), ValueScaling::Linear)
.color(Color::rgb(120, 120, 120));
})
}
```

It's very plug-and-play, you only need to call `enqueue_buffer()` in your
plugin's process function to use it!

Check out the book, or the [examples](examples) to learn how to work with these
buffers.
Check out the book or the [examples](examples) to familiarize yourself with this
system.

## 🍔 Composing views

A core feature of Cyma is composability.

For example, by combining views such as the `Grid`, `UnitRuler`, and
`PeakGraph`, you can make this real-time peak analyzer.
For example, by combining views such as the `Grid`, `UnitRuler`, `Graph`, and
`Histogram` you can make this real-time peak graph with an RMS plot and a
histogram overlay.

![Peak visualizer](doc/composability_demo.png)

```rust
fn peak_graph(cx: &mut Context) {
HStack::new(cx, |cx| {
ZStack::new(cx, |cx| {
Grid::new(
cx,
ValueScaling::Linear,
(-32., 8.),
vec![6.0, 0.0, -6.0, -12.0, -18.0, -24.0, -30.0],
Orientation::Horizontal,
)
.color(Color::rgb(60, 60, 60));

Graph::new(cx, Data::peak_buffer, (-32.0, 8.0), ValueScaling::Decibels)
.color(Color::rgba(255, 255, 255, 160))
.background_color(Color::rgba(255, 255, 255, 60));
})
.background_color(Color::rgb(16, 16, 16));

UnitRuler::new(
cx,
(-32.0, 8.0),
ValueScaling::Linear,
vec![
(6.0, "6db"),
(0.0, "0db"),
(-6.0, "-6db"),
(-12.0, "-12db"),
(-18.0, "-18db"),
(-24.0, "-24db"),
(-30.0, "-30db"),
],
Orientation::Vertical,
)
.font_size(12.)
.color(Color::rgb(160, 160, 160))
.width(Pixels(32.));
})
.col_between(Pixels(8.));
}
ZStack::new(cx, |cx| {
Grid::new(
cx,
ValueScaling::Linear,
(-32., 8.0),
vec![6.0, 0.0, -6.0, -12.0, -18.0, -24.0, -30.0],
Orientation::Horizontal,
)
.border_width(Pixels(0.5))
.color(Color::rgb(30, 30, 30));
Graph::peak(
cx,
bus.clone(),
10.0,
50.0,
(-32.0, 8.0),
ValueScaling::Decibels,
)
.color(Color::rgba(255, 255, 255, 60))
.background_color(Color::rgba(255, 255, 255, 30));
Graph::rms(
cx,
bus.clone(),
10.0,
250.0,
(-32.0, 8.0),
ValueScaling::Decibels,
)
.color(Color::rgba(255, 92, 92, 128));
Histogram::new(cx, bus.clone(), 250.0, (-32.0, 8.0), ValueScaling::Decibels)
.width(Pixels(64.0))
.color(Color::rgba(64, 128, 255, 64))
.background_color(Color::rgba(64, 128, 255, 32));
UnitRuler::new(
cx,
(-32.0, 8.0),
ValueScaling::Linear,
vec![
(6.0, "6 dB"),
(0.0, "0 dB"),
(-6.0, "-6 dB"),
(-12.0, "-12 dB"),
(-18.0, "-18 dB"),
(-24.0, "-24 dB"),
(-30.0, "-30 dB"),
],
Orientation::Vertical,
)
.font_size(12.)
.color(Color::rgb(220, 220, 220))
.right(Pixels(8.0))
.left(Stretch(1.0));
});
```

## 🙋 Contributing
Expand Down
14 changes: 4 additions & 10 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,8 @@

# Guides

- [Composing a Peak Graph](./peak_graph/overview.md)
- [Setting up a PeakBuffer](./peak_graph/peak_buffer_setup.md)
- [Displaying a Graph](./peak_graph/graph_setup.md)
- [Adding Grid Lines](./peak_graph/composing.md)
- [Composing a Peak Graph]()
- [Setting up a PeakBuffer]()
- [Displaying a Graph]()
- [Adding Grid Lines]()
- [Plotting Loudness]()
- [Building a Filter UI]()
- [Adding Some Knobs]()
- [Adding a Spectrogram]()
- [Styling the Spectrogram]()
- [Plotting the Filter Curve]()
- [Making it All Interactive]()
Binary file modified doc/composability_demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/visualizers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "histogram"
name = "benchmark_lots_of_visualizers"
version = "0.1.0"
edition = "2021"
description = "A histogram built using Cyma"
description = "Lots of peak graphs"

[lib]
crate-type = ["cdylib", "lib"]
Expand Down
1 change: 1 addition & 0 deletions examples/benchmark_lots_of_visualizers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Visualizers
89 changes: 89 additions & 0 deletions examples/benchmark_lots_of_visualizers/src/editor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use cyma::prelude::*;
use nih_plug::editor::Editor;
use nih_plug_vizia::widgets::ResizeHandle;
use nih_plug_vizia::{assets, create_vizia_editor, vizia::prelude::*, ViziaState, ViziaTheming};
use std::sync::Arc;

#[derive(Lens, Clone)]
pub(crate) struct Data {
bus: Arc<MonoBus>,
}

impl Data {
pub(crate) fn new(bus: Arc<MonoBus>) -> Self {
Self { bus }
}
}

impl Model for Data {}

pub(crate) fn default_state() -> Arc<ViziaState> {
ViziaState::new(|| (1920, 1080))
}

const W: usize = 16;
const H: usize = 12;

pub(crate) fn create(editor_data: Data, editor_state: Arc<ViziaState>) -> Option<Box<dyn Editor>> {
const SPACING: Units = Pixels(1.0);

create_vizia_editor(editor_state, ViziaTheming::default(), move |cx, _| {
assets::register_noto_sans_light(cx);
editor_data.clone().build(cx);
VStack::new(cx, |cx| {
for _ in 0..H {
HStack::new(cx, |cx| {
for _ in 0..W {
visualizer(cx);
}
})
.row_between(SPACING);
}

Label::new(
cx,
format!("Cyma {} - Lots of Visualizers", env!("CARGO_PKG_VERSION")).as_str(),
)
.space(Pixels(8.0))
.color(Color::rgb(180, 180, 180));
})
.background_color(Color::rgb(0, 0, 0))
.row_between(SPACING);

ResizeHandle::new(cx);
})
}

fn visualizer(cx: &mut Context) {
ZStack::new(cx, |cx| {
Grid::new(
cx,
ValueScaling::Linear,
(-32., 8.0),
vec![6.0, 0.0, -6.0, -12.0, -18.0, -24.0, -30.0],
Orientation::Horizontal,
)
.border_width(Pixels(0.5))
.color(Color::rgb(30, 30, 30));
Graph::peak(
cx,
Data::bus,
10.0,
50.0,
(-32.0, 8.0),
ValueScaling::Decibels,
)
.color(Color::rgba(255, 255, 255, 60))
.background_color(Color::rgba(255, 255, 255, 30));
Graph::rms(
cx,
Data::bus,
10.0,
250.0,
(-32.0, 8.0),
ValueScaling::Decibels,
)
.color(Color::rgba(255, 92, 92, 128));
})
.background_color(Color::rgb(16, 16, 16));
}
Loading
Loading