mirror of
https://github.com/storytold/soundcraft.git
synced 2026-10-28 20:46:58 -06:00
fix(midi-editor): Quantize snaps to the grid the editor shows (#226)
This commit is contained in:
@@ -84,6 +84,19 @@ pub fn show(app: &mut SoundApp, ui: &mut Ui) {
|
||||
regular(11.0),
|
||||
t.text_dim,
|
||||
);
|
||||
let grid_ticks = match app.engine.session().edit.grid {
|
||||
soundcraft_time::GridValue::Note { value, dotted, triplet } => {
|
||||
let mut g = value.ticks();
|
||||
if dotted {
|
||||
g = g * 3 / 2;
|
||||
}
|
||||
if triplet {
|
||||
g = g * 2 / 3;
|
||||
}
|
||||
g.max(1)
|
||||
}
|
||||
_ => TICKS_PER_QUARTER / 4,
|
||||
};
|
||||
// Header toolbar: whole-clip MIDI operations.
|
||||
let bar = Rect::from_min_max(pos2(header.max.x - 330.0, header.min.y + 1.0), pos2(header.max.x - 6.0, header.max.y - 1.0));
|
||||
let mut tb = ui.new_child(egui::UiBuilder::new().max_rect(bar).layout(egui::Layout::right_to_left(egui::Align::Center)));
|
||||
@@ -99,7 +112,7 @@ pub fn show(app: &mut SoundApp, ui: &mut Ui) {
|
||||
op = Some(("event.change_velocity", json!({"add": 10})));
|
||||
}
|
||||
if tb.small_button("Quantize").on_hover_text("Quantize to the grid").clicked() {
|
||||
op = Some(("event.quantize", json!({"grid": "1/16", "strength": 100})));
|
||||
op = Some(("event.quantize", json!({"grid": grid_ticks, "strength": 100})));
|
||||
}
|
||||
if let Some((id, mut p)) = op {
|
||||
p["clips"] = json!([cid.0]);
|
||||
@@ -109,19 +122,6 @@ pub fn show(app: &mut SoundApp, ui: &mut Ui) {
|
||||
let sr = s.sample_rate;
|
||||
let base_tick = s.tempo.samples_to_ticks(clip.start, sr);
|
||||
let len_ticks = (s.tempo.samples_to_ticks(clip.end(), sr) - base_tick).max(1);
|
||||
let grid_ticks = match s.edit.grid {
|
||||
soundcraft_time::GridValue::Note { value, dotted, triplet } => {
|
||||
let mut g = value.ticks();
|
||||
if dotted {
|
||||
g = g * 3 / 2;
|
||||
}
|
||||
if triplet {
|
||||
g = g * 2 / 3;
|
||||
}
|
||||
g.max(1)
|
||||
}
|
||||
_ => TICKS_PER_QUARTER / 4,
|
||||
};
|
||||
let roll = Rect::from_min_max(pos2(full.min.x + KEY_W, header.max.y), pos2(full.max.x - 4.0, full.max.y - VEL_H - 4.0));
|
||||
let keys = Rect::from_min_max(pos2(full.min.x, roll.min.y), pos2(roll.min.x, roll.max.y));
|
||||
let vel = Rect::from_min_max(pos2(roll.min.x, roll.max.y + 4.0), pos2(roll.max.x, full.max.y - 2.0));
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
//! The MIDI Editor's Quantize button snaps to the grid the editor shows.
|
||||
use egui::vec2;
|
||||
use egui_kittest::{Harness, kittest::Queryable};
|
||||
use serde_json::json;
|
||||
use soundcraft_ui_egui::{Services, SoundApp};
|
||||
|
||||
fn quantize_on(grid: &str) -> i64 {
|
||||
let mut app = SoundApp::new(soundcraft_engine::Engine::default(), None, Services::default());
|
||||
app.run("track.new", json!({"name": "Grid Check", "kind": "midi"})).unwrap();
|
||||
let clip = app.run("midi.new_clip", json!({"track": "Grid Check", "start": 0, "end": 96_000})).unwrap()["clip"].clone();
|
||||
app.run("midi.note_add", json!({"clip": clip, "pitch": 60, "start_ticks": 300, "length_ticks": 240})).unwrap();
|
||||
app.run("edit.select", json!({"clips": [clip]})).unwrap();
|
||||
app.run("view.grid", json!({"value": grid})).unwrap();
|
||||
app.ui.show_midi_editor = true;
|
||||
let mut h = Harness::builder().with_size(vec2(1600.0, 1000.0)).build_ui_state(
|
||||
|ui, app: &mut SoundApp| {
|
||||
app.logic(&ui.ctx().clone());
|
||||
app.ui(ui);
|
||||
},
|
||||
app,
|
||||
);
|
||||
h.run_steps(5);
|
||||
h.get_by_label("Quantize").click();
|
||||
h.run_steps(3);
|
||||
let notes = h.state_mut().run("midi.notes", json!({"clip": clip})).unwrap();
|
||||
assert_eq!(notes["notes"][0]["length"], 240, "{notes}");
|
||||
notes["notes"][0]["start"].as_i64().unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quantize_follows_a_quarter_note_grid() {
|
||||
assert_eq!(quantize_on("1/4"), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quantize_follows_a_sixteenth_note_grid() {
|
||||
assert_eq!(quantize_on("1/16"), 240);
|
||||
}
|
||||
Reference in New Issue
Block a user