Giter Site home page Giter Site logo

223230 / cyma Goto Github PK

View Code? Open in Web Editor NEW
31.0 2.0 1.0 1 MB

Composable views for nih-plug UIs made using VIZIA

Home Page: https://223230.github.io/cyma/book

License: Mozilla Public License 2.0

Rust 100.00%
audio-visualizer nih-plug rust-audio rust-gui vizia

cyma's Introduction

Cyma

Documentation | Book | Examples | Contributing

Composable views and associated data structures for nih-plug UIs made using VIZIA.


โœจ Overview

Cyma is a collection of flexible, composable views that you can use to make rich 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)

cyma.0601.mp4

Wanna see the code behind this? It's this example!

๐Ÿงฐ What's included

Check out this project to see what views will eventually be added. Do you think something's missing? File a feature request so it can be added!

๐Ÿ“Š Visualizers

General/Utility

  • Grid backdrop
  • Unit ruler

Peak/Waveform Analysis

  • Meter
  • Graph
  • Oscilloscope
  • Static waveform

Stereo imaging

  • Lissajous

Spectral analysis

  • Spectrum Analyzer

โ“ Example

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

Oscilloscope

Oscilloscope::new(
    cx,
    Data::oscilloscope_buffer,
    (-1.2, 1.2),
    ValueScaling::Linear,
)
.background_color(Color::rgba(120, 120, 120));

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.

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 to learn how to work with these buffers.

๐Ÿ” 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.

Peak visualizer

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.));
}

๐Ÿ™‹ Contributing

If you have questions about Cyma, need help with something, or want to show off what you built using it, head over to the Discussions tab.

If you want to contribute through issues and code contributions, read the Contributing Guidelines first

๐Ÿ“ƒ License

This project is licensed under the MPL.

cyma's People

Contributors

exa04 avatar magnetophon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

magnetophon

cyma's Issues

Graph drawing error

Description:
When a graph is used with .fill_from(0.0), and the value is also 0.0, the graph-outline of the left most part of the graph does not get drawn:

Screenshots:
image
image

Desktop (please complete the following information):

  • OS: Linux 6.6.25
  • VST Host / DAW (if applicable): Jack standalone

set_range() for Graph, Grid, Meter, etc.

Just like PeakBuffer and MinimaBuffer have set_duration() to set the scale in one direction, the views that include a range should have a set_range() to set the scale in the other direction.

Don't use mutexes on the DSP thread

Overview

Mutexes are discouraged on the Plugin thread - they can lead to lock-ups, glitches, and general performance issues.

Currently, many of Cyma's visualizers synchronize with the Plugin data through some VisualizerBuffer that is inside an Arc<Mutex>. The Mutex needs to be locked every time a new chunk of audio needs to be enqueued. This can introduce glitches when many plug-ins are used.

Outline

This is going to be a pretty big change. It should be well though-out. Here's a rough outline of what needs to be done:

  • Extensively test the possible alternatives before banking on them
  • Introduce as few breaking changes on Cyma's public side as possible
  • Settle on a ring buffer and re-write all others on it - preferrably, this buffer should replace Cyma's RingBuffer
  • Update docs and book to reflect the changes
  • Update the examples

Possible Solutions

There are many different options to consider. This is a non-exhaustive list of some of them:

SPSC/SPMC lock-free structures

Something like a real-time circular buffer that can be written to via a single producer, which doesn't need to be locked and is wait-free. The consumer may need to be locked by the editor, which is generally fine as the real-time requirements of the DSP thread don't really extend to the GUI. So far, I haven't found a lock-free circular buffer that perfectly fits our needs.

Multiple buffering

Offers a producer and a consumer for writing and reading. The editor thread could receive an Arc<Mutex<BufferOutput>> while the plugin thread keeps a struct that can be immediately accessed for input. One downside would be that the plugin thread may have data that is a few frames newer than whatever the editor thread has. In my humble opinion, this is fine, because people are more sensitive to sonic latency than graphical latency.

This thread synchronization mechanism is also used in the nih-plug Diopser plugin, for the spectrum analyzer. In fact, Cyma's own spectrum analyzer also uses triple buffering, because it is basically a copy of Diopser's analyzer.

"Atomic Arcs" via arc_swap

The ArcSwap type is a container for an Arc that can be changed atomically.
Semantically, it is similar to something like Atomic<Arc<T>> (if there was such a thing) or RwLock<Arc<T>> (but without the need for the locking). It is optimized for read-mostly scenarios, with consistent performance characteristics.

From the arc_swap docs

Honestly, I don't know much about this crate, but I wanted to put it here in case it might be helpful.

Arrays of atomic values

I'm kind of unsure whether this would even be possible, putting aside the obvious overhead that atomic operations incur. Just wanted to put this idea out there, I guess...

Use modifiers where applicable

Modifiers should be used in place of those parameters that are often left untouched or frequently set to a default. For example:

  • ValueScaling
  • Inversion (f.e. of peak graph, etc)
  • Orientation

Universal `Meter` and `Graph`

Currently, "*Graph" and "*Meter" views are planned for:

  • Peak volume
  • Loudness
  • Gain reduction

...and more may come in the future. The issue is that implementing these as seperate views will lead to a lot of code duplication as the logic behind different types of meters and graphs is largely identical - aside from the scaling of values.

So, maybe an abstract solution that is a bit more flexible would be better. Something like a universal Graph and Meter that can display peak volume, gain reduction, and anything else you throw at it, depending on the context. In the same vein, the scaling (linear/dB/freq/etc) should probably be handled using some ubiquitous scaling Enum that all visualizers can go on to use.

It's worth thinking about this as soon as possible as it would involve a major breaking change, especially as more views get added.

LoudnessBuffer for Meter, Graph, etc.

This buffer will need to compute the loudness of incoming audio in large overlapping blocks by pre-filtering each channel, taking their respective mean square values, summing them, gating the result, and averaging it. Making this work will involve adding (likely 2nd order IIR) filters to Cyma, either through an external crate, or a new internal filter struct.

This PDF explains the process in great detail.

Feature request: gain reduction meter

As a reminder of our conversation on Discord:

For dynamics processors, it would be great to have a gain reduction meter.
A gain change meter, that can go up as well as down, would be even better.
This is since upward compressors and expanders dynamically add gain instead of reducing it.

I imagine it will be a line at 0dB, and an area when it goes above or below that.
Does that make sense?

Thanks again for this wonderful library!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.