mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 15:25:01 +01:00
hans' patches for MIDI note resizing++
git-svn-id: svn://localhost/ardour2/branches/3.0@3184 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
022c45361e
commit
6554200e66
10 changed files with 207 additions and 58 deletions
|
|
@ -63,6 +63,7 @@ CanvasMidiEvent::selected(bool yn)
|
||||||
bool
|
bool
|
||||||
CanvasMidiEvent::on_event(GdkEvent* ev)
|
CanvasMidiEvent::on_event(GdkEvent* ev)
|
||||||
{
|
{
|
||||||
|
MidiStreamView *streamview = _region.midi_stream_view();
|
||||||
static uint8_t drag_delta_note = 0;
|
static uint8_t drag_delta_note = 0;
|
||||||
static double drag_delta_x = 0;
|
static double drag_delta_x = 0;
|
||||||
static double last_x, last_y;
|
static double last_x, last_y;
|
||||||
|
|
@ -147,16 +148,17 @@ CanvasMidiEvent::on_event(GdkEvent* ev)
|
||||||
drag_delta_x += dx;
|
drag_delta_x += dx;
|
||||||
|
|
||||||
// Snap to note rows
|
// Snap to note rows
|
||||||
if (abs(dy) < _region.midi_stream_view()->note_height()) {
|
if (abs(dy) < streamview->note_height()) {
|
||||||
dy = 0.0;
|
dy = 0.0;
|
||||||
} else {
|
} else {
|
||||||
int8_t this_delta_note;
|
int8_t this_delta_note;
|
||||||
if (dy > 0)
|
if (dy > 0) {
|
||||||
this_delta_note = (int8_t)ceil(dy / _region.midi_stream_view()->note_height() / 2.0);
|
this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
|
||||||
else
|
} else {
|
||||||
this_delta_note = (int8_t)floor(dy / _region.midi_stream_view()->note_height() / 2.0);
|
this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
|
||||||
|
}
|
||||||
drag_delta_note -= this_delta_note;
|
drag_delta_note -= this_delta_note;
|
||||||
dy = _region.midi_stream_view()->note_height() * this_delta_note;
|
dy = streamview->note_height() * this_delta_note;
|
||||||
last_y = last_y + dy;
|
last_y = last_y + dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,38 +12,39 @@ bool
|
||||||
CanvasNote::on_event(GdkEvent* ev)
|
CanvasNote::on_event(GdkEvent* ev)
|
||||||
{
|
{
|
||||||
double event_x;
|
double event_x;
|
||||||
static double middle_point, pressed_x, last_x;
|
static double middle_point, last_x;
|
||||||
Gdk::Cursor cursor;
|
Gdk::Cursor cursor;
|
||||||
static NoteEnd note_end;
|
static NoteEnd note_end;
|
||||||
|
Editing::MidiEditMode edit_mode = _region.get_trackview().editor.current_midi_edit_mode();
|
||||||
|
|
||||||
switch(ev->type) {
|
switch(ev->type) {
|
||||||
case GDK_BUTTON_PRESS:
|
case GDK_BUTTON_PRESS:
|
||||||
if (ev->button.button == 2) {
|
if (ev->button.button == 2 ||
|
||||||
|
(ev->button.button == 1 &&
|
||||||
|
edit_mode == Editing::MidiEditResize)) {
|
||||||
|
double region_start = _region.get_position_pixels();
|
||||||
event_x = ev->button.x;
|
event_x = ev->button.x;
|
||||||
middle_point = x1() + (x2() - x1()) / 2.0L;
|
middle_point = region_start + x1() + (x2() - x1()) / 2.0L;
|
||||||
|
|
||||||
if(event_x <= middle_point) {
|
if(event_x <= middle_point) {
|
||||||
cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
|
cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
|
||||||
last_x = x1();
|
|
||||||
note_end = NOTE_ON;
|
note_end = NOTE_ON;
|
||||||
} else {
|
} else {
|
||||||
cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
|
cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
|
||||||
last_x = x2();
|
|
||||||
note_end = NOTE_OFF;
|
note_end = NOTE_OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
_item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, ev->motion.time);
|
_item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, ev->motion.time);
|
||||||
|
|
||||||
if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) {
|
if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) {
|
||||||
_mouse2_state = AbsoluteResize;
|
_note_state = AbsoluteResize;
|
||||||
} else {
|
} else {
|
||||||
_mouse2_state = RelativeResize;
|
_note_state = RelativeResize;
|
||||||
}
|
}
|
||||||
|
|
||||||
pressed_x = event_x;
|
|
||||||
|
|
||||||
_region.note_selected(this, true);
|
_region.note_selected(this, true);
|
||||||
_region.begin_resizing(note_end);
|
_region.begin_resizing(note_end);
|
||||||
|
last_x = event_x;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -51,13 +52,13 @@ CanvasNote::on_event(GdkEvent* ev)
|
||||||
case GDK_MOTION_NOTIFY:
|
case GDK_MOTION_NOTIFY:
|
||||||
event_x = ev->motion.x;
|
event_x = ev->motion.x;
|
||||||
|
|
||||||
if (_mouse2_state == RelativeResize) {
|
if (_note_state == RelativeResize) {
|
||||||
_region.update_resizing(note_end, event_x - last_x, true);
|
_region.update_resizing(note_end, event_x - last_x, true);
|
||||||
last_x = event_x;
|
last_x = event_x;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_mouse2_state == AbsoluteResize) {
|
if (_note_state == AbsoluteResize) {
|
||||||
_region.update_resizing(note_end, event_x, false);
|
_region.update_resizing(note_end, event_x, false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -65,17 +66,17 @@ CanvasNote::on_event(GdkEvent* ev)
|
||||||
case GDK_BUTTON_RELEASE:
|
case GDK_BUTTON_RELEASE:
|
||||||
event_x = ev->button.x;
|
event_x = ev->button.x;
|
||||||
|
|
||||||
switch (_mouse2_state) {
|
switch (_note_state) {
|
||||||
case RelativeResize: // Clicked
|
case RelativeResize: // Clicked
|
||||||
_item->ungrab(ev->button.time);
|
_item->ungrab(ev->button.time);
|
||||||
_region.commit_resizing(note_end, event_x, true);
|
_region.commit_resizing(note_end, event_x, true);
|
||||||
_mouse2_state = None;
|
_note_state = None;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case AbsoluteResize: // Clicked
|
case AbsoluteResize: // Clicked
|
||||||
_item->ungrab(ev->button.time);
|
_item->ungrab(ev->button.time);
|
||||||
_region.commit_resizing(note_end, event_x, false);
|
_region.commit_resizing(note_end, event_x, false);
|
||||||
_mouse2_state = None;
|
_note_state = None;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -55,18 +55,17 @@ public:
|
||||||
NOTE_OFF
|
NOTE_OFF
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Mouse2State {
|
enum NoteState {
|
||||||
None,
|
None,
|
||||||
RelativeResize,
|
RelativeResize,
|
||||||
AbsoluteResize
|
AbsoluteResize
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Mouse2State _mouse2_state;
|
NoteState _note_state;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// single click resizing with mouse-2
|
|
||||||
void resize_note(double pressed_x, double event_x, double middle_point);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Gnome
|
} // namespace Gnome
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ MOUSEMODE(MouseNote)
|
||||||
|
|
||||||
MIDIEDITMODE(MidiEditPencil)
|
MIDIEDITMODE(MidiEditPencil)
|
||||||
MIDIEDITMODE(MidiEditSelect)
|
MIDIEDITMODE(MidiEditSelect)
|
||||||
|
MIDIEDITMODE(MidiEditResize)
|
||||||
MIDIEDITMODE(MidiEditErase)
|
MIDIEDITMODE(MidiEditErase)
|
||||||
|
|
||||||
/* Changing this order will break the menu */
|
/* Changing this order will break the menu */
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,7 @@ Gdk::Cursor* Editor::fader_cursor = 0;
|
||||||
Gdk::Cursor* Editor::speaker_cursor = 0;
|
Gdk::Cursor* Editor::speaker_cursor = 0;
|
||||||
Gdk::Cursor* Editor::midi_pencil_cursor = 0;
|
Gdk::Cursor* Editor::midi_pencil_cursor = 0;
|
||||||
Gdk::Cursor* Editor::midi_select_cursor = 0;
|
Gdk::Cursor* Editor::midi_select_cursor = 0;
|
||||||
|
Gdk::Cursor* Editor::midi_resize_cursor = 0;
|
||||||
Gdk::Cursor* Editor::midi_erase_cursor = 0;
|
Gdk::Cursor* Editor::midi_erase_cursor = 0;
|
||||||
Gdk::Cursor* Editor::wait_cursor = 0;
|
Gdk::Cursor* Editor::wait_cursor = 0;
|
||||||
Gdk::Cursor* Editor::timebar_cursor = 0;
|
Gdk::Cursor* Editor::timebar_cursor = 0;
|
||||||
|
|
@ -1390,6 +1391,7 @@ Editor::build_cursors ()
|
||||||
timebar_cursor = new Gdk::Cursor(LEFT_PTR);
|
timebar_cursor = new Gdk::Cursor(LEFT_PTR);
|
||||||
midi_pencil_cursor = new Gdk::Cursor (PENCIL);
|
midi_pencil_cursor = new Gdk::Cursor (PENCIL);
|
||||||
midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
|
midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
|
||||||
|
midi_resize_cursor = new Gdk::Cursor (SIZING);
|
||||||
midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
|
midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3084,6 +3086,9 @@ Editor::setup_midi_toolbar ()
|
||||||
midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
|
midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
|
||||||
midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
|
midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
|
||||||
midi_tool_buttons.push_back (&midi_tool_select_button);
|
midi_tool_buttons.push_back (&midi_tool_select_button);
|
||||||
|
midi_tool_resize_button.add (*(manage (new Image (::get_icon("strip_width")))));
|
||||||
|
midi_tool_resize_button.set_relief(Gtk::RELIEF_NONE);
|
||||||
|
midi_tool_buttons.push_back (&midi_tool_resize_button);
|
||||||
midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
|
midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
|
||||||
midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
|
midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
|
||||||
midi_tool_buttons.push_back (&midi_tool_erase_button);
|
midi_tool_buttons.push_back (&midi_tool_erase_button);
|
||||||
|
|
@ -3093,29 +3098,34 @@ Editor::setup_midi_toolbar ()
|
||||||
midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
|
midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
|
||||||
|
|
||||||
midi_tool_button_box.set_border_width (2);
|
midi_tool_button_box.set_border_width (2);
|
||||||
midi_tool_button_box.set_spacing(4);
|
|
||||||
midi_tool_button_box.set_spacing(1);
|
midi_tool_button_box.set_spacing(1);
|
||||||
midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
|
midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
|
||||||
midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
|
midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
|
||||||
|
midi_tool_button_box.pack_start(midi_tool_resize_button, true, true);
|
||||||
midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
|
midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
|
||||||
midi_tool_button_box.set_homogeneous(true);
|
midi_tool_button_box.set_homogeneous(true);
|
||||||
|
|
||||||
midi_tool_pencil_button.set_name ("MouseModeButton");
|
midi_tool_pencil_button.set_name ("MouseModeButton");
|
||||||
midi_tool_select_button.set_name ("MouseModeButton");
|
midi_tool_select_button.set_name ("MouseModeButton");
|
||||||
|
midi_tool_resize_button.set_name ("MouseModeButton");
|
||||||
midi_tool_erase_button.set_name ("MouseModeButton");
|
midi_tool_erase_button.set_name ("MouseModeButton");
|
||||||
|
|
||||||
ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
|
ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
|
||||||
ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
|
ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
|
||||||
|
ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_resize_button, _("Resize Notes"));
|
||||||
ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
|
ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
|
||||||
|
|
||||||
midi_tool_pencil_button.unset_flags (CAN_FOCUS);
|
midi_tool_pencil_button.unset_flags (CAN_FOCUS);
|
||||||
midi_tool_select_button.unset_flags (CAN_FOCUS);
|
midi_tool_select_button.unset_flags (CAN_FOCUS);
|
||||||
|
midi_tool_resize_button.unset_flags (CAN_FOCUS);
|
||||||
midi_tool_erase_button.unset_flags (CAN_FOCUS);
|
midi_tool_erase_button.unset_flags (CAN_FOCUS);
|
||||||
|
|
||||||
midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
|
midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
|
||||||
&Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
|
&Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
|
||||||
midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
|
midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
|
||||||
&Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
|
&Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
|
||||||
|
midi_tool_resize_button.signal_toggled().connect (bind (mem_fun(*this,
|
||||||
|
&Editor::midi_edit_mode_toggled), Editing::MidiEditResize));
|
||||||
midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
|
midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
|
||||||
&Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
|
&Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -990,6 +990,7 @@ class Editor : public PublicEditor
|
||||||
static Gdk::Cursor* speaker_cursor;
|
static Gdk::Cursor* speaker_cursor;
|
||||||
static Gdk::Cursor* midi_pencil_cursor;
|
static Gdk::Cursor* midi_pencil_cursor;
|
||||||
static Gdk::Cursor* midi_select_cursor;
|
static Gdk::Cursor* midi_select_cursor;
|
||||||
|
static Gdk::Cursor* midi_resize_cursor;
|
||||||
static Gdk::Cursor* midi_erase_cursor;
|
static Gdk::Cursor* midi_erase_cursor;
|
||||||
static Gdk::Cursor* wait_cursor;
|
static Gdk::Cursor* wait_cursor;
|
||||||
static Gdk::Cursor* timebar_cursor;
|
static Gdk::Cursor* timebar_cursor;
|
||||||
|
|
@ -1642,6 +1643,7 @@ public:
|
||||||
Gtkmm2ext::TearOff* midi_tool_tearoff;
|
Gtkmm2ext::TearOff* midi_tool_tearoff;
|
||||||
Gtk::ToggleButton midi_tool_pencil_button;
|
Gtk::ToggleButton midi_tool_pencil_button;
|
||||||
Gtk::ToggleButton midi_tool_select_button;
|
Gtk::ToggleButton midi_tool_select_button;
|
||||||
|
Gtk::ToggleButton midi_tool_resize_button;
|
||||||
Gtk::ToggleButton midi_tool_erase_button;
|
Gtk::ToggleButton midi_tool_erase_button;
|
||||||
GroupedButtons *midi_tool_button_set;
|
GroupedButtons *midi_tool_button_set;
|
||||||
void midi_edit_mode_toggled (Editing::MidiEditMode m);
|
void midi_edit_mode_toggled (Editing::MidiEditMode m);
|
||||||
|
|
|
||||||
|
|
@ -414,6 +414,11 @@ Editor::midi_edit_mode_toggled (MidiEditMode m)
|
||||||
set_midi_edit_mode (m);
|
set_midi_edit_mode (m);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MidiEditResize:
|
||||||
|
if (midi_tool_resize_button.get_active())
|
||||||
|
set_midi_edit_mode (m);
|
||||||
|
break;
|
||||||
|
|
||||||
case MidiEditErase:
|
case MidiEditErase:
|
||||||
if (midi_tool_erase_button.get_active())
|
if (midi_tool_erase_button.get_active())
|
||||||
set_midi_edit_mode (m);
|
set_midi_edit_mode (m);
|
||||||
|
|
@ -453,6 +458,10 @@ Editor::set_midi_edit_mode (MidiEditMode m, bool force)
|
||||||
midi_tool_select_button.set_active (true);
|
midi_tool_select_button.set_active (true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MidiEditResize:
|
||||||
|
midi_tool_resize_button.set_active (true);
|
||||||
|
break;
|
||||||
|
|
||||||
case MidiEditErase:
|
case MidiEditErase:
|
||||||
midi_tool_erase_button.set_active (true);
|
midi_tool_erase_button.set_active (true);
|
||||||
break;
|
break;
|
||||||
|
|
@ -479,6 +488,10 @@ Editor::set_midi_edit_cursor (MidiEditMode m)
|
||||||
current_canvas_cursor = midi_select_cursor;
|
current_canvas_cursor = midi_select_cursor;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MidiEditResize:
|
||||||
|
current_canvas_cursor = midi_resize_cursor;
|
||||||
|
break;
|
||||||
|
|
||||||
case MidiEditErase:
|
case MidiEditErase:
|
||||||
current_canvas_cursor = midi_erase_cursor;
|
current_canvas_cursor = midi_erase_cursor;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,9 @@ MidiRegionView::canvas_event(GdkEvent* ev)
|
||||||
} else if (ev->key.keyval == GDK_Shift_L || ev->key.keyval == GDK_Control_L) {
|
} else if (ev->key.keyval == GDK_Shift_L || ev->key.keyval == GDK_Control_L) {
|
||||||
_mouse_state = SelectTouchDragging;
|
_mouse_state = SelectTouchDragging;
|
||||||
return true;
|
return true;
|
||||||
|
} else if (ev->key.keyval == GDK_Escape) {
|
||||||
|
clear_selection();
|
||||||
|
_mouse_state = None;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -304,6 +307,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
|
||||||
case Pressed: // Clicked
|
case Pressed: // Clicked
|
||||||
switch (trackview.editor.current_midi_edit_mode()) {
|
switch (trackview.editor.current_midi_edit_mode()) {
|
||||||
case MidiEditSelect:
|
case MidiEditSelect:
|
||||||
|
case MidiEditResize:
|
||||||
clear_selection();
|
clear_selection();
|
||||||
break;
|
break;
|
||||||
case MidiEditPencil:
|
case MidiEditPencil:
|
||||||
|
|
@ -382,7 +386,7 @@ MidiRegionView::clear_events()
|
||||||
clear_selection();
|
clear_selection();
|
||||||
|
|
||||||
MidiGhostRegion* gr;
|
MidiGhostRegion* gr;
|
||||||
for (vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) {
|
for (std::vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) {
|
||||||
if ((gr = dynamic_cast<MidiGhostRegion*>(*g)) != 0) {
|
if ((gr = dynamic_cast<MidiGhostRegion*>(*g)) != 0) {
|
||||||
gr->clear_events();
|
gr->clear_events();
|
||||||
}
|
}
|
||||||
|
|
@ -686,7 +690,7 @@ MidiRegionView::add_note(const boost::shared_ptr<Note> note)
|
||||||
|
|
||||||
MidiGhostRegion* gr;
|
MidiGhostRegion* gr;
|
||||||
|
|
||||||
for (vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) {
|
for (std::vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) {
|
||||||
if ((gr = dynamic_cast<MidiGhostRegion*>(*g)) != 0) {
|
if ((gr = dynamic_cast<MidiGhostRegion*>(*g)) != 0) {
|
||||||
gr->add_note(ev_rect);
|
gr->add_note(ev_rect);
|
||||||
}
|
}
|
||||||
|
|
@ -818,6 +822,38 @@ MidiRegionView::note_dropped(CanvasMidiEvent* ev, double dt, uint8_t dnote)
|
||||||
{
|
{
|
||||||
// TODO: This would be faster/nicer with a MoveCommand that doesn't need to copy...
|
// TODO: This would be faster/nicer with a MoveCommand that doesn't need to copy...
|
||||||
if (_selection.find(ev) != _selection.end()) {
|
if (_selection.find(ev) != _selection.end()) {
|
||||||
|
uint8_t lowest_note_in_selection = midi_stream_view()->lowest_note();
|
||||||
|
uint8_t highest_note_in_selection = midi_stream_view()->highest_note();
|
||||||
|
uint8_t highest_note_difference = 0;
|
||||||
|
|
||||||
|
// find highest and lowest notes first
|
||||||
|
for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ) {
|
||||||
|
Selection::iterator next = i;
|
||||||
|
++next;
|
||||||
|
|
||||||
|
uint8_t pitch = (*i)->note()->note();
|
||||||
|
lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
|
||||||
|
highest_note_in_selection = std::max(highest_note_in_selection, pitch);
|
||||||
|
|
||||||
|
i = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
cerr << "dnote: " << (int) dnote << endl;
|
||||||
|
cerr << "lowest note (streamview): " << int(midi_stream_view()->lowest_note())
|
||||||
|
<< " highest note (streamview): " << int(midi_stream_view()->highest_note()) << endl;
|
||||||
|
cerr << "lowest note (selection): " << int(lowest_note_in_selection) << " highest note(selection): "
|
||||||
|
<< int(highest_note_in_selection) << endl;
|
||||||
|
cerr << "selection size: " << _selection.size() << endl;
|
||||||
|
cerr << "Highest note in selection: " << (int) highest_note_in_selection << endl;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Make sure the note pitch does not exceed the MIDI standard range
|
||||||
|
if (dnote <= 127 && (highest_note_in_selection + dnote > 127)) {
|
||||||
|
highest_note_difference = highest_note_in_selection - 127;
|
||||||
|
cerr << "Highest note difference: " << (int) highest_note_difference;
|
||||||
|
}
|
||||||
|
|
||||||
start_delta_command();
|
start_delta_command();
|
||||||
|
|
||||||
for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ) {
|
for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ) {
|
||||||
|
|
@ -828,16 +864,57 @@ MidiRegionView::note_dropped(CanvasMidiEvent* ev, double dt, uint8_t dnote)
|
||||||
const boost::shared_ptr<Note> copy(new Note(*(*i)->note().get()));
|
const boost::shared_ptr<Note> copy(new Note(*(*i)->note().get()));
|
||||||
|
|
||||||
copy->set_time((*i)->note()->time() + dt);
|
copy->set_time((*i)->note()->time() + dt);
|
||||||
copy->set_note((*i)->note()->note() + dnote);
|
if(copy->time() < 0) {
|
||||||
|
copy->set_time(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t new_pitch = (*i)->note()->note() + dnote - highest_note_difference;
|
||||||
|
if(new_pitch > 127) {
|
||||||
|
new_pitch = 127;
|
||||||
|
}
|
||||||
|
|
||||||
|
lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
|
||||||
|
highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
|
||||||
|
|
||||||
|
copy->set_note(new_pitch);
|
||||||
|
|
||||||
command_add_note(copy);
|
command_add_note(copy);
|
||||||
|
|
||||||
_selection.erase(i);
|
_selection.erase(i);
|
||||||
i = next;
|
i = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply_command();
|
apply_command();
|
||||||
|
|
||||||
|
//cerr << "new lowest note (selection): " << int(lowest_note_in_selection) << " new highest note(selection): " << int(highest_note_in_selection) << endl;
|
||||||
|
|
||||||
|
// care about notes being moved beyond the upper/lower bounds on the canvas
|
||||||
|
if(lowest_note_in_selection < midi_stream_view()->lowest_note() ||
|
||||||
|
highest_note_in_selection > midi_stream_view()->highest_note()
|
||||||
|
) {
|
||||||
|
//cerr << "resetting note range" << endl;
|
||||||
|
midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
MidiRegionView::snap_to(double x)
|
||||||
|
{
|
||||||
|
PublicEditor &editor = trackview.editor;
|
||||||
|
|
||||||
|
nframes_t frame = editor.pixel_to_frame(x);
|
||||||
|
editor.snap_to(frame);
|
||||||
|
return (double) editor.frame_to_pixel(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
MidiRegionView::get_position_pixels(void)
|
||||||
|
{
|
||||||
|
nframes_t region_frame = get_position();
|
||||||
|
return trackview.editor.frame_to_pixel(region_frame);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiRegionView::begin_resizing(CanvasNote::NoteEnd note_end)
|
MidiRegionView::begin_resizing(CanvasNote::NoteEnd note_end)
|
||||||
|
|
@ -852,18 +929,34 @@ MidiRegionView::begin_resizing(CanvasNote::NoteEnd note_end)
|
||||||
NoteResizeData *resize_data = new NoteResizeData();
|
NoteResizeData *resize_data = new NoteResizeData();
|
||||||
resize_data->canvas_note = note;
|
resize_data->canvas_note = note;
|
||||||
|
|
||||||
SimpleRect *resize_rect = new SimpleRect(*group, note->x1(), note->y1(), note->x2(), note->y2());
|
// create a new SimpleRect from the note which will be the resize preview
|
||||||
|
SimpleRect *resize_rect =
|
||||||
|
new SimpleRect(
|
||||||
|
*group,
|
||||||
|
note->x1(),
|
||||||
|
note->y1(),
|
||||||
|
note->x2(),
|
||||||
|
note->y2());
|
||||||
|
|
||||||
uint fill_color = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(), 128);
|
// calculate the colors: get the color settings
|
||||||
|
uint fill_color =
|
||||||
|
UINT_RGBA_CHANGE_A(
|
||||||
|
ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(),
|
||||||
|
128);
|
||||||
|
|
||||||
|
// make the resize preview notes more transparent and bright
|
||||||
fill_color = UINT_INTERPOLATE(fill_color, 0xFFFFFF40, 0.5);
|
fill_color = UINT_INTERPOLATE(fill_color, 0xFFFFFF40, 0.5);
|
||||||
|
|
||||||
|
// calculate color based on note velocity
|
||||||
resize_rect->property_fill_color_rgba() =
|
resize_rect->property_fill_color_rgba() =
|
||||||
UINT_INTERPOLATE(
|
UINT_INTERPOLATE(
|
||||||
note_fill_color(note->note()->velocity()),
|
note_fill_color(note->note()->velocity()),
|
||||||
fill_color,
|
fill_color,
|
||||||
0.85);
|
0.85);
|
||||||
|
|
||||||
resize_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get();
|
resize_rect->property_outline_color_rgba() =
|
||||||
|
ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get();
|
||||||
|
|
||||||
resize_data->resize_rect = resize_rect;
|
resize_data->resize_rect = resize_rect;
|
||||||
|
|
||||||
if(note_end == CanvasNote::NOTE_ON) {
|
if(note_end == CanvasNote::NOTE_ON) {
|
||||||
|
|
@ -877,38 +970,33 @@ MidiRegionView::begin_resizing(CanvasNote::NoteEnd note_end)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
|
||||||
MidiRegionView::snap_to(double x)
|
|
||||||
{
|
|
||||||
PublicEditor &editor = trackview.editor;
|
|
||||||
|
|
||||||
nframes_t frame = editor.pixel_to_frame(x);
|
|
||||||
editor.snap_to(frame);
|
|
||||||
return (double) editor.frame_to_pixel(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiRegionView::update_resizing(CanvasNote::NoteEnd note_end, double dx, bool relative)
|
MidiRegionView::update_resizing(CanvasNote::NoteEnd note_end, double x, bool relative)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
for (std::vector<NoteResizeData *>::iterator i = _resize_data.begin(); i != _resize_data.end(); ++i) {
|
for (std::vector<NoteResizeData *>::iterator i = _resize_data.begin(); i != _resize_data.end(); ++i) {
|
||||||
SimpleRect *resize_rect = (*i)->resize_rect;
|
SimpleRect *resize_rect = (*i)->resize_rect;
|
||||||
CanvasNote *canvas_note = (*i)->canvas_note;
|
CanvasNote *canvas_note = (*i)->canvas_note;
|
||||||
|
|
||||||
|
const double region_start = get_position_pixels();
|
||||||
|
|
||||||
if(relative) {
|
if(relative) {
|
||||||
(*i)->current_x = (*i)->current_x + dx;
|
(*i)->current_x = (*i)->current_x + x;
|
||||||
} else {
|
} else {
|
||||||
(*i)->current_x = dx;
|
// x is in track relative, transform it to region relative
|
||||||
|
(*i)->current_x = x - region_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
double current_x = (*i)->current_x;
|
double current_x = (*i)->current_x;
|
||||||
|
|
||||||
if(note_end == CanvasNote::NOTE_ON) {
|
if(note_end == CanvasNote::NOTE_ON) {
|
||||||
resize_rect->property_x1() = snap_to(current_x);
|
// because snapping works on world coordinates we have to transform current_x
|
||||||
|
// to world coordinates before snapping and transform it back afterwards
|
||||||
|
resize_rect->property_x1() = snap_to(region_start + current_x) - region_start;
|
||||||
resize_rect->property_x2() = canvas_note->x2();
|
resize_rect->property_x2() = canvas_note->x2();
|
||||||
} else {
|
} else {
|
||||||
resize_rect->property_x2() = snap_to(current_x);
|
// because snapping works on world coordinates we have to transform current_x
|
||||||
|
// to world coordinates before snapping and transform it back afterwards
|
||||||
|
resize_rect->property_x2() = snap_to(region_start + current_x) - region_start;
|
||||||
resize_rect->property_x1() = canvas_note->x1();
|
resize_rect->property_x1() = canvas_note->x1();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -923,14 +1011,18 @@ MidiRegionView::commit_resizing(CanvasNote::NoteEnd note_end, double event_x, bo
|
||||||
CanvasNote *canvas_note = (*i)->canvas_note;
|
CanvasNote *canvas_note = (*i)->canvas_note;
|
||||||
SimpleRect *resize_rect = (*i)->resize_rect;
|
SimpleRect *resize_rect = (*i)->resize_rect;
|
||||||
double current_x = (*i)->current_x;
|
double current_x = (*i)->current_x;
|
||||||
|
const double region_start = get_position_pixels();
|
||||||
|
|
||||||
if(!relative) {
|
if(!relative) {
|
||||||
current_x = event_x;
|
// event_x is in track relative, transform it to region relative
|
||||||
|
current_x = event_x - region_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
nframes_t current_frame = trackview.editor.pixel_to_frame(current_x);
|
// because snapping works on world coordinates we have to transform current_x
|
||||||
|
// to world coordinates before snapping and transform it back afterwards
|
||||||
|
nframes_t current_frame = trackview.editor.pixel_to_frame(current_x + region_start);
|
||||||
trackview.editor.snap_to(current_frame);
|
trackview.editor.snap_to(current_frame);
|
||||||
|
current_frame -= get_position();
|
||||||
|
|
||||||
const boost::shared_ptr<Note> copy(new Note(*(canvas_note->note().get())));
|
const boost::shared_ptr<Note> copy(new Note(*(canvas_note->note().get())));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -132,8 +132,34 @@ class MidiRegionView : public RegionView
|
||||||
void move_selection(double dx, double dy);
|
void move_selection(double dx, double dy);
|
||||||
void note_dropped(ArdourCanvas::CanvasMidiEvent* ev, double dt, uint8_t dnote);
|
void note_dropped(ArdourCanvas::CanvasMidiEvent* ev, double dt, uint8_t dnote);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is needed to subtract the region start in pixels
|
||||||
|
* from world coordinates submitted by the mouse
|
||||||
|
*/
|
||||||
|
double get_position_pixels(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called by CanvasMidiNote when resizing starts,
|
||||||
|
* i.e. when the user presses mouse-2 on the note
|
||||||
|
* @param note_end which end of the note, NOTE_ON or NOTE_OFF
|
||||||
|
*/
|
||||||
void begin_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end);
|
void begin_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end);
|
||||||
void update_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end, double dx, bool relative);
|
|
||||||
|
/**
|
||||||
|
* This function is called while the user moves the mouse when resizing notes
|
||||||
|
* @param note_end which end of the note, NOTE_ON or NOTE_OFF
|
||||||
|
* @param x the difference in mouse motion, ie the motion difference if relative=true
|
||||||
|
* or the absolute mouse position (track-relative) if relative is false
|
||||||
|
* @param relative true if relative resizing is taking place, false if absolute resizing
|
||||||
|
*/
|
||||||
|
void update_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end, double x, bool relative);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called while the user releases the mouse button when resizing notes
|
||||||
|
* @param note_end which end of the note, NOTE_ON or NOTE_OFF
|
||||||
|
* @param event_x the absolute mouse position (track-relative)
|
||||||
|
* @param relative true if relative resizing is taking place, false if absolute resizing
|
||||||
|
*/
|
||||||
void commit_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end, double event_x, bool relative);
|
void commit_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end, double event_x, bool relative);
|
||||||
|
|
||||||
enum MouseState { None, Pressed, SelectTouchDragging, SelectRectDragging, AddDragging, EraseTouchDragging };
|
enum MouseState { None, Pressed, SelectTouchDragging, SelectRectDragging, AddDragging, EraseTouchDragging };
|
||||||
|
|
@ -147,11 +173,11 @@ class MidiRegionView : public RegionView
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/* this constructor allows derived types
|
/**
|
||||||
to specify their visibility requirements
|
* this constructor allows derived types
|
||||||
to the TimeAxisViewItem parent class
|
* to specify their visibility requirements
|
||||||
|
* to the TimeAxisViewItem parent class
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MidiRegionView (ArdourCanvas::Group *,
|
MidiRegionView (ArdourCanvas::Group *,
|
||||||
RouteTimeAxisView&,
|
RouteTimeAxisView&,
|
||||||
boost::shared_ptr<ARDOUR::MidiRegion>,
|
boost::shared_ptr<ARDOUR::MidiRegion>,
|
||||||
|
|
@ -177,6 +203,11 @@ class MidiRegionView : public RegionView
|
||||||
void clear_selection_except(ArdourCanvas::CanvasMidiEvent* ev);
|
void clear_selection_except(ArdourCanvas::CanvasMidiEvent* ev);
|
||||||
void clear_selection() { clear_selection_except(NULL); }
|
void clear_selection() { clear_selection_except(NULL); }
|
||||||
void update_drag_selection(double last_x, double x, double last_y, double y);
|
void update_drag_selection(double last_x, double x, double last_y, double y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function provides the snap function for pixel units (double)
|
||||||
|
* instead of nframes_t
|
||||||
|
*/
|
||||||
double snap_to(double x);
|
double snap_to(double x);
|
||||||
|
|
||||||
double _default_note_length;
|
double _default_note_length;
|
||||||
|
|
|
||||||
|
|
@ -143,8 +143,6 @@ Parser::trace_event (Parser &p, byte *msg, size_t len)
|
||||||
eventType type;
|
eventType type;
|
||||||
ostream *o;
|
ostream *o;
|
||||||
|
|
||||||
cerr << "TRACE\n";
|
|
||||||
|
|
||||||
if ((o = trace_stream) == NULL) { /* can be asynchronously removed */
|
if ((o = trace_stream) == NULL) { /* can be asynchronously removed */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue