Skip to content

Commit

Permalink
port gain example GUI to new API
Browse files Browse the repository at this point in the history
  • Loading branch information
micahrj committed Dec 3, 2024
1 parent 79dd7cf commit 6d96cdf
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 10 deletions.
2 changes: 1 addition & 1 deletion examples/gain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ formats = ["clap", "vst3"]

[dependencies]
coupler = { workspace = true, features = ["derive"] }
coupler-reflector = { path = "../../coupler-reflector" }
reflector = { git = "https://github.com/coupler-rs/reflector", rev = "eb40c59a71470077b4f58a26685796d1609ea8ed" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
197 changes: 188 additions & 9 deletions examples/gain/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
use std::cell::RefCell;
use std::io::{self, Read, Write};
use std::rc::Rc;

use serde::{Deserialize, Serialize};

use coupler::format::clap::*;
use coupler::format::vst3::*;
use coupler::params::{ParamId, ParamValue};
use coupler::view::{ParentWindow, RawParent, Size, View};
use coupler::{buffers::*, bus::*, engine::*, events::*, host::*, params::*, plugin::*, view::*};

use coupler_reflector::PluginWindow;
use reflector::graphics::Renderer;
use reflector::platform::{
App, AppMode, AppOptions, Bitmap, Cursor, MouseButton, Point, RawWindow, Response, Result,
Window, WindowContext, WindowOptions,
};

#[derive(Params, Serialize, Deserialize, Clone)]
struct GainParams {
Expand All @@ -26,7 +34,7 @@ pub struct Gain {

impl Plugin for Gain {
type Engine = GainEngine;
type View = PluginWindow;
type View = GainView;

fn info() -> PluginInfo {
PluginInfo {
Expand Down Expand Up @@ -84,13 +92,8 @@ impl Plugin for Gain {
}
}

fn view(&mut self, _host: ViewHost, parent: &ParentWindow) -> Self::View {
let size = Size {
width: 512.0,
height: 512.0,
};

PluginWindow::open(parent, size).unwrap()
fn view(&mut self, host: ViewHost, parent: &ParentWindow) -> Self::View {
GainView::open(host, parent, &self.params).unwrap()
}
}

Expand Down Expand Up @@ -146,3 +149,179 @@ impl Engine for GainEngine {
}
}
}

struct Gesture {
start_mouse_pos: Point,
start_value: f32,
}

struct ViewState {
host: ViewHost,
params: Rc<RefCell<GainParams>>,
renderer: Renderer,
framebuffer: Vec<u32>,
mouse_pos: Point,
gesture: Option<Gesture>,
}

impl ViewState {
fn new(host: ViewHost, params: Rc<RefCell<GainParams>>) -> ViewState {
ViewState {
host,
params,
renderer: Renderer::new(),
framebuffer: Vec::new(),
mouse_pos: Point { x: -1.0, y: -1.0 },
gesture: None,
}
}

fn update_cursor(&self, window: &Window) {
let pos = self.mouse_pos;
if pos.x >= 96.0 && pos.x < 160.0 && pos.y >= 96.0 && pos.y < 160.0 {
window.set_cursor(Cursor::SizeNs);
} else {
window.set_cursor(Cursor::Arrow);
}
}

fn handle_event(&mut self, cx: &WindowContext, event: reflector::platform::Event) -> Response {
use reflector::graphics::{Affine, Color, Path, Point};
use reflector::platform::Event;

match event {
Event::Frame => {
let scale = cx.window().scale();
let size = cx.window().size();
let width = (size.width * scale) as usize;
let height = (size.height * scale) as usize;
self.framebuffer.resize(width * height, 0xFF000000);

let mut canvas = self.renderer.canvas(&mut self.framebuffer, width, height);

canvas.clear(Color::rgba(21, 26, 31, 255));

let transform = Affine::scale(scale as f32);

let value = self.params.borrow().gain;

let center = Point::new(128.0, 128.0);
let radius = 32.0;
let angle1 = 0.75 * std::f32::consts::PI;
let angle2 = angle1 + value * 1.5 * std::f32::consts::PI;
let mut path = Path::new();
path.move_to(center + radius * Point::new(angle1.cos(), angle1.sin()));
path.arc(radius, angle1, angle2);
path.line_to(center + (radius - 4.0) * Point::new(angle2.cos(), angle2.sin()));
path.arc(radius - 4.0, angle2, angle1);
path.close();
canvas.fill_path(&path, transform, Color::rgba(240, 240, 245, 255));

let center = Point::new(128.0, 128.0);
let radius = 32.0;
let angle = 0.75 * std::f32::consts::PI;
let span = 1.5 * std::f32::consts::PI;
let mut path = Path::new();
path.move_to(center + radius * Point::new(angle.cos(), angle.sin()));
path.arc(radius, angle, angle + span);
path.line_to(center + (radius - 4.0) * Point::new(-angle.cos(), angle.sin()));
path.arc(radius - 4.0, angle + span, angle);
path.close();
canvas.stroke_path(&path, 1.0, transform, Color::rgba(240, 240, 245, 255));

cx.window().present(Bitmap::new(&self.framebuffer, width, height));
}
Event::MouseMove(pos) => {
self.mouse_pos = pos;
if let Some(gesture) = &self.gesture {
let delta = -0.005 * (pos.y - gesture.start_mouse_pos.y) as f32;
let new_value = (gesture.start_value + delta).clamp(0.0, 1.0);
self.host.set_param(0, new_value as f64);
self.params.borrow_mut().gain = new_value;
} else {
self.update_cursor(cx.window());
}
}
Event::MouseDown(button) => {
if button == MouseButton::Left {
let pos = self.mouse_pos;
if pos.x >= 96.0 && pos.x < 160.0 && pos.y >= 96.0 && pos.y < 160.0 {
cx.window().set_cursor(Cursor::SizeNs);
self.host.begin_gesture(0);
let value = self.params.borrow().gain;
self.host.set_param(0, value as f64);
self.params.borrow_mut().gain = value;
self.gesture = Some(Gesture {
start_mouse_pos: pos,
start_value: value,
});
return Response::Capture;
}
}
}
Event::MouseUp(button) => {
if button == MouseButton::Left {
if self.gesture.is_some() {
self.host.end_gesture(0);
self.gesture = None;
self.update_cursor(cx.window());
return Response::Capture;
}
}
}
_ => {}
}

Response::Ignore
}
}

pub struct GainView {
#[allow(unused)]
app: App,
window: Window,
params: Rc<RefCell<GainParams>>,
}

impl GainView {
fn open(host: ViewHost, parent: &ParentWindow, params: &GainParams) -> Result<GainView> {
let app = AppOptions::new().mode(AppMode::Guest).build()?;

let mut options = WindowOptions::new();
options.size(reflector::platform::Size::new(256.0, 256.0));

let raw_parent = match parent.as_raw() {
RawParent::Win32(window) => RawWindow::Win32(window),
RawParent::Cocoa(view) => RawWindow::Cocoa(view),
RawParent::X11(window) => RawWindow::X11(window),
};
unsafe { options.raw_parent(raw_parent) };

let params = Rc::new(RefCell::new(params.clone()));
let mut state = ViewState::new(host, Rc::clone(&params));
let window = options.open(app.handle(), move |cx, event| state.handle_event(cx, event))?;

window.show();

Ok(GainView {
app,
window,
params,
})
}
}

impl View for GainView {
fn size(&self) -> Size {
let size = self.window.size();

Size {
width: size.width,
height: size.height,
}
}

fn param_changed(&mut self, id: ParamId, value: ParamValue) {
self.params.borrow_mut().set_param(id, value);
}
}

0 comments on commit 6d96cdf

Please sign in to comment.