Closed hi-ogawa closed 1 year ago
# build clap examples https://github.com/robbert-vdh/nih-plug/
cargo xtask bundle sine # gain_gui_egui etc...
# build clap-host https://github.com/free-audio/clap-host
cmake --preset ninja-system
cmake --build --preset ninja-system
# run plugin
CLAP_HOST_FORCE_PLUGIN=../nih-plug/target/bundled/sine.clap ./builds/ninja-system/host/Debug/clap-host
# run plugin as jack app
cargo build -p gain_gui_egui
./target/debug/gain_gui_egui -b jack
EDIT: implemented in https://github.com/hi-ogawa/nih-plug-examples
// TODO:
// - [x] render keyboard
// - [ ] handle event
// - click
// - key input
// - [ ] manage state (both external and internal?)
pub fn piano_ui(ui: &mut egui::Ui) -> egui::Response {
let padding = 1.0;
let key_size = egui::vec2(12.0, 42.0);
let key_size_black = egui::vec2(12.0, 22.0);
let num_white_keys = 7;
let (response, painter) = ui.allocate_painter(
key_size * egui::vec2(num_white_keys as f32, 1.0),
egui::Sense::click(),
);
// TODO
if response.clicked() {}
for i in 0..7 {
let rect = egui::Rect::from_min_size(
response.rect.min + egui::vec2((i as f32) * key_size.x + padding, 0.0),
key_size - 2.0 * egui::vec2(padding, padding),
);
painter.rect_filled(rect, egui::Rounding::none(), egui::Color32::WHITE);
}
for i in (0..2).chain(3..6) {
let rect = egui::Rect::from_min_size(
response.rect.min + egui::vec2(((i as f32) + 0.5) * key_size.x + padding, 0.0),
key_size_black - 2.0 * egui::vec2(padding, padding),
);
painter.rect_filled(rect, egui::Rounding::none(), egui::Color32::BLACK);
}
response
}
fn generate_note_rects() -> Vec<(usize, egui::Rect)> {
// TODO: parameters
let padding = 1.0;
let key_size = egui::vec2(20.0, 80.0);
// define Rect to represent each key in "local" coordinates
let mut note_rects: Vec<(usize, egui::Rect)> = vec![];
for i in 0..(14 * 2) {
// no black key between E-F and B-C
if i % 14 == 5 || i % 14 == 13 {
continue;
}
let pos = egui::pos2(0.5 * (i as f32) * (key_size.x + 2.0 * padding), 0.0);
let size = if i % 2 == 0 {
key_size
} else {
key_size * egui::vec2(1.0, 0.5)
};
let rect = egui::Rect::from_min_size(pos, size);
note_rects.push((i, rect));
}
note_rects.sort_by_key(|(i, _)| i % 2); // black key has higher z
note_rects
}
pub fn piano_ui(ui: &mut egui::Ui) -> egui::Response {
let note_rects = generate_note_rects();
let paint_rect = note_rects
.iter()
.fold(egui::Rect::NOTHING, |acc, &(_, rect)| acc.union(rect));
let (mut response, painter) =
ui.allocate_painter(paint_rect.size(), egui::Sense::click_and_drag());
for &(i, rect) in ¬e_rects {
let rect = rect.translate(response.rect.min.to_vec2());
let color = if i % 2 == 0 {
egui::Color32::WHITE
} else {
egui::Color32::BLACK
};
painter.rect_filled(rect, egui::Rounding::from(1.0), color);
if let Some(pointer_pos) = response.interact_pointer_pos() {
if rect.contains(pointer_pos) {
response.mark_changed();
dbg!("yeah!", i); // TODO
}
}
}
response
}
Closing since enough interesting things are explored already:
AudioWorkletProcessor
AudioContext
initializationnih-plugin ideas
https://github.com/hi-ogawa/nih-plug-examples
implement midi keyboard
implement fluidsynth driver as nih-plug
nih-plug exporter to audioworklet
ui via electron/tauri?
rewrite audio related imgui widget to egui?
rewrite calf style nob/slider to egui?
why not winit (https://github.com/rust-windowing/winit) instead of baseview (https://github.com/RustAudio/baseview/)?
concurrent programming refresher
pipewire ideas