28 #include <sigc++/signal.h>
30 #include "midi++/midnam_patch.h"
48 #include "canvas/debug.h"
49 #include "canvas/text.h"
95 #define MIDI_BP_ZERO ((Config->get_first_midi_bank_is_zero())?0:1)
101 uint32_t basic_color)
102 :
RegionView (parent, tv, r, spu, basic_color)
103 , _current_range_min(0)
104 , _current_range_max(0)
105 , _region_relative_time_converter(r->session().tempo_map(), r->
position())
106 , _source_relative_time_converter(r->session().tempo_map(), r->
position() - r->
start())
109 , _note_diff_command (0)
111 , _step_edit_cursor (0)
112 , _step_edit_cursor_width (1.0)
113 , _step_edit_cursor_position (0.0)
114 , _channel_selection_scoped_note (0)
115 , _temporary_note_group (0)
118 , _sort_needed (true)
119 , _optimization_iterator (_events.end())
121 , _no_sound_notes (false)
122 , _last_display_zoom (0)
125 , _grabbed_keyboard (false)
127 , _mouse_changed_selection (false)
146 uint32_t basic_color,
149 :
RegionView (parent, tv, r, spu, basic_color, recording, visibility)
150 , _current_range_min(0)
151 , _current_range_max(0)
152 , _region_relative_time_converter(r->session().tempo_map(), r->
position())
153 , _source_relative_time_converter(r->session().tempo_map(), r->
position() - r->
start())
156 , _note_diff_command (0)
158 , _step_edit_cursor (0)
159 , _step_edit_cursor_width (1.0)
160 , _step_edit_cursor_position (0.0)
161 , _channel_selection_scoped_note (0)
162 , _temporary_note_group (0)
165 , _sort_needed (true)
166 , _optimization_iterator (_events.end())
168 , _no_sound_notes (false)
169 , _last_display_zoom (0)
172 , _grabbed_keyboard (false)
174 , _mouse_changed_selection (false)
192 if (p ==
"display-first-midi-bank-as-zero") {
200 :
sigc::trackable(other)
202 , _current_range_min(0)
203 , _current_range_max(0)
204 , _region_relative_time_converter(other.region_relative_time_converter())
205 , _source_relative_time_converter(other.source_relative_time_converter())
207 , _note_group (new
ArdourCanvas::Container (get_canvas_group()))
208 , _note_diff_command (0)
210 , _step_edit_cursor (0)
211 , _step_edit_cursor_width (1.0)
212 , _step_edit_cursor_position (0.0)
213 , _channel_selection_scoped_note (0)
214 , _temporary_note_group (0)
217 , _sort_needed (true)
218 , _optimization_iterator (_events.end())
220 , _no_sound_notes (false)
221 , _last_display_zoom (0)
224 , _grabbed_keyboard (false)
226 , _mouse_changed_selection (false)
233 , _current_range_min(0)
234 , _current_range_max(0)
235 , _region_relative_time_converter(other.region_relative_time_converter())
236 , _source_relative_time_converter(other.source_relative_time_converter())
238 , _note_group (new
ArdourCanvas::Container (get_canvas_group()))
239 , _note_diff_command (0)
241 , _step_edit_cursor (0)
242 , _step_edit_cursor_width (1.0)
243 , _step_edit_cursor_position (0.0)
244 , _channel_selection_scoped_note (0)
245 , _temporary_note_group (0)
248 , _sort_needed (true)
249 , _optimization_iterator (_events.end())
251 , _no_sound_notes (false)
252 , _last_display_zoom (0)
255 , _grabbed_keyboard (false)
257 , _mouse_changed_selection (false)
300 group->raise_to_top();
363 case GDK_ENTER_NOTIFY:
370 case GDK_LEAVE_NOTIFY:
378 if (
scroll (&ev->scroll)) {
386 case GDK_KEY_RELEASE:
389 case GDK_BUTTON_PRESS:
392 case GDK_BUTTON_RELEASE:
396 case GDK_MOTION_NOTIFY:
399 return motion (&ev->motion);
453 Keyboard::magic_widget_grab_focus();
473 Keyboard::magic_widget_drop_focus();
489 if (ev->button != 1) {
496 if (m == MouseContent && Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())) {
517 double event_x, event_y;
519 if (ev->button != 1) {
526 group->canvas_to_item (event_x, event_y);
549 if (Keyboard::is_insert_note_event(ev)) {
551 double event_x, event_y;
555 group->canvas_to_item (event_x, event_y);
615 Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier()) &&
621 Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())) {
638 (*i)->hide_velocity ();
648 if (m == MouseDraw || (m == MouseContent && Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier()))) {
654 }
else if (m == MouseContent) {
656 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
662 }
else if (m == MouseRange) {
699 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
708 bool fine = !Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier);
709 bool together = Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier);
711 if (ev->direction == GDK_SCROLL_UP) {
713 }
else if (ev->direction == GDK_SCROLL_DOWN) {
731 bool unmodified = Keyboard::no_modifier_keys_pressed (ev);
733 if (unmodified && (ev->keyval == GDK_Alt_L || ev->keyval == GDK_Alt_R)) {
737 }
else if (ev->keyval == GDK_Escape && unmodified) {
741 }
else if (ev->keyval == GDK_comma || ev->keyval == GDK_period) {
743 bool start = (ev->keyval == GDK_comma);
744 bool end = (ev->keyval == GDK_period);
745 bool shorter = Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier);
746 bool fine = Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier);
752 }
else if ((ev->keyval == GDK_BackSpace || ev->keyval == GDK_Delete) && unmodified) {
761 }
else if (ev->keyval == GDK_Tab || ev->keyval == GDK_ISO_Left_Tab) {
765 if (Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier)) {
766 goto_previous_note (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
768 goto_next_note (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
775 }
else if (ev->keyval == GDK_Up) {
777 bool allow_smush = Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier);
778 bool fine = !Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier);
779 bool together = Keyboard::modifier_state_contains (ev->state, Keyboard::Level4Modifier);
781 if (Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier)) {
788 }
else if (ev->keyval == GDK_Down) {
790 bool allow_smush = Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier);
791 bool fine = !Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier);
792 bool together = Keyboard::modifier_state_contains (ev->state, Keyboard::Level4Modifier);
794 if (Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier)) {
801 }
else if (ev->keyval == GDK_Left) {
803 bool fine = !Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier);
807 }
else if (ev->keyval == GDK_Right) {
809 bool fine = !Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier);
813 }
else if (ev->keyval == GDK_c && unmodified) {
817 }
else if (ev->keyval == GDK_v && unmodified) {
846 uint8_t current_channel = (*
_selection.begin())->note()->channel ();
848 int ret = channel_dialog.run ();
851 case Gtk::RESPONSE_OK:
862 Selection::iterator next = i;
882 uint8_t current_velocity = (*
_selection.begin())->note()->velocity ();
884 int ret = velocity_dialog.run ();
887 case Gtk::RESPONSE_OK:
893 uint8_t new_velocity = velocity_dialog.
velocity ();
898 Selection::iterator next = i;
925 if (length < 2 * DBL_EPSILON) {
946 new NoteType (chan, beat_time, length, (uint8_t)note, velocity));
970 for (std::vector<GhostRegion*>::iterator g =
ghosts.begin(); g !=
ghosts.end(); ++g) {
971 if ((gr = dynamic_cast<MidiGhostRegion*>(*g)) != 0) {
976 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
1019 if (show_velocity) {
1056 bool commit =
false;
1072 if (as_subcommand) {
1081 if (add_or_remove) {
1111 if ((*_optimization_iterator)->note() == note) {
1123 Events::iterator it;
1126 if (*((*it)->note()) == note) {
1137 MidiModel::Notes notes;
1140 for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) {
1158 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
1159 if ((*i)->note()->length() > 0) {
1172 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
1173 (*i)->invalidate ();
1181 bool empty_when_starting =
_events.empty();
1183 for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) {
1207 set<boost::shared_ptr<NoteType> >::iterator it;
1209 if (*(*it) == *note) {
1225 if (!empty_when_starting) {
1226 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ) {
1227 if (!(*i)->valid ()) {
1229 for (vector<GhostRegion*>::iterator j =
ghosts.begin(); j !=
ghosts.end(); ++j) {
1269 for (uint8_t i = 0; i < 16; ++i) {
1282 if ((*i)->channel() != channel) {
1294 bool have_periodic_system_messages =
false;
1295 bool display_periodic_messages =
true;
1304 if (mev->is_spp() || mev->is_mtc_quarter() || mev->is_mtc_full()) {
1305 have_periodic_system_messages =
true;
1311 if (have_periodic_system_messages) {
1323 if (zoom > (video_frame*4)) {
1324 display_periodic_messages =
false;
1328 display_periodic_messages =
false;
1339 if (mev->is_spp() || mev->is_mtc_quarter() || mev->is_mtc_full()) {
1340 if (!display_periodic_messages) {
1348 for (uint32_t b = 0; b < (*i)->size(); ++b) {
1349 str << int((*i)->buffer()[b]);
1350 if (b != (*i)->size() -1) {
1354 string text = str.str();
1452 height != old_height);
1485 for (Events::const_iterator i =
_events.begin(); i !=
_events.end(); ++i) {
1496 if (
Note* cnote = dynamic_cast<Note*>(event)) {
1498 const double y0 = 1. + floor (
midi_stream_view()->note_to_y(note->note()));
1501 if (y0 < 0 || y1 >=
_height) {
1519 }
else if (
Hit* chit = dynamic_cast<Hit*>(event)) {
1541 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
1547 ghosts.push_back (ghost);
1564 for (
unsigned i = 0; i < 128; ++i) {
1616 for (
unsigned i = 0; i < 128; ++i) {
1647 const std::vector< boost::shared_ptr<NoteType> > notes(1, note);
1681 const bool outside = ((note_start_frames <= -tick_frames) ||
1695 if ((sus = dynamic_cast<Note*>(note))) {
1697 }
else if ((hit = dynamic_cast<Hit*>(note))) {
1718 if (note->
length() > 0) {
1740 ArdourCanvas::Rectangle::TOP|
1741 ArdourCanvas::Rectangle::LEFT|
1742 ArdourCanvas::Rectangle::BOTTOM));
1752 if (update_ghost_regions) {
1753 for (std::vector<GhostRegion*>::iterator i =
ghosts.begin(); i !=
ghosts.end(); ++i) {
1786 if (update_ghost_regions) {
1787 for (std::vector<GhostRegion*>::iterator i =
ghosts.begin(); i !=
ghosts.end(); ++i) {
1832 for (std::vector<GhostRegion*>::iterator g =
ghosts.begin(); g !=
ghosts.end(); ++g) {
1833 if ((gr = dynamic_cast<MidiGhostRegion*>(*g)) != 0) {
1843 event->show_velocity();
1874 if (end_frame > region_end) {
1929 if (region_frames < 0 || region_frames >=
_region->
length()) {
1930 patch_change->
hide();
1932 patch_change->
show();
1935 patch_change->
hide ();
1941 MIDI::Name::PatchPrimaryKey
1944 return MIDI::Name::PatchPrimaryKey (p->program(), p->bank());
1951 return pc->time() <= time && pc->channel() == channel;
1968 key.set_bank((*i)->bank());
1969 key.set_program((*i)->program ());
1979 string name =
_(
"alter patch change");
1983 if (pc.
patch()->program() != new_patch.program()) {
1987 int const new_bank = new_patch.bank();
1988 if (pc.
patch()->bank() != new_bank) {
2002 string name =
_(
"alter patch change");
2006 if (old_change->time() != new_change.
time()) {
2010 if (old_change->channel() != new_change.
channel()) {
2014 if (old_change->program() != new_change.
program()) {
2018 if (old_change->bank() != new_change.
bank()) {
2038 string name =
_(
"add patch change");
2042 c->
add (MidiModel::PatchChangePtr (
2088 key.set_bank(key.bank() + delta);
2090 key.set_program(key.program() + delta);
2115 if ((*i)->selected()) {
2140 Selection::iterator tmp = i;
2143 (*i)->set_selected (
false);
2144 (*i)->hide_velocity ();
2155 Keyboard::magic_widget_drop_focus();
2183 if (selection_was_empty &&
_entered) {
2185 Keyboard::magic_widget_grab_focus();
2196 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
2206 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
2208 if (t >= start && t <= end) {
2217 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
2218 if ((*i)->selected()) {
2233 list<boost::shared_ptr<NoteType> >::iterator n;
2235 for (n = notes.begin(); n != notes.end(); ++n) {
2248 uint8_t low_note = 127;
2249 uint8_t high_note = 0;
2253 if (extend && !have_selection) {
2260 if ((*i)->note()->note() < low_note) {
2261 low_note = (*i)->note()->note();
2263 if ((*i)->note()->note() > high_note) {
2264 high_note = (*i)->note()->note();
2271 if (!extend && (low_note == high_note) && (high_note == notenum)) {
2280 low_note = min (low_note, notenum);
2281 high_note = max (high_note, notenum);
2286 for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) {
2292 if (((1 << note->
channel()) & channel_mask) != 0) {
2294 if ((note->
note() >= low_note && note->
note() <= high_note)) {
2297 }
else if (note->
note() == notenum) {
2323 for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) {
2328 if (note->
note() == notenum && (((0x0001 << note->
channel()) & channel_mask) != 0)) {
2347 editor.get_selection().add (
this);
2364 if ((*i)->note()->end_time() > latest) {
2365 latest = (*i)->note()->end_time();
2367 if ((*i)->note()->time() < earliest) {
2368 earliest = (*i)->note()->time();
2372 if (ev->
note()->end_time() > latest) {
2373 latest = ev->
note()->end_time();
2376 if (ev->
note()->time() < earliest) {
2377 earliest = ev->
note()->time();
2380 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
2384 if (((*i)->note()->time() >= earliest && (*i)->note()->end_time() <= latest) ||
2385 ((*i)->note()->time() <= earliest && (*i)->note()->end_time() >= latest)) {
2409 const double y0 = max(0.0, gy0 - y);
2410 const double y1 = max(0.0, gy1 - y);
2416 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
2417 if ((*i)->x0() < x1 && (*i)->x1() > x0 && (*i)->y0() < y1 && (*i)->y1() > y0) {
2419 if (!(*i)->selected()) {
2422 }
else if ((*i)->selected() && !extend) {
2429 typedef std::list<Selectable*> Selectables;
2433 Selectables selectables;
2435 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
2436 a->second->get_selectables(start, end, gy0, gy1, selectables);
2437 for (Selectables::const_iterator s = selectables.begin(); s != selectables.end(); ++s) {
2458 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
2459 if (((*i)->y1() >= y1 && (*i)->y1() <= y2)) {
2461 if (!(*i)->selected()) {
2464 }
else if ((*i)->selected() && !extend) {
2473 Selection::iterator i =
_selection.find (ev);
2479 Keyboard::magic_widget_drop_focus();
2489 editor.get_selection().remove (
this);
2501 if (selection_was_empty &&
_entered) {
2503 Keyboard::magic_widget_grab_focus();
2508 if (selection_was_empty) {
2510 editor.get_selection().add (
this);
2517 typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
2518 PossibleChord to_play;
2522 if ((*i)->note()->time() < earliest) {
2523 earliest = (*i)->note()->time();
2528 if ((*i)->note()->time() == earliest) {
2529 to_play.push_back ((*i)->note());
2531 (*i)->move_event(dx, dy);
2536 if (to_play.size() > 1) {
2538 PossibleChord shifted;
2540 for (PossibleChord::iterator n = to_play.begin(); n != to_play.end(); ++n) {
2542 moved_note->
set_note (moved_note->
note() + cumulative_dy);
2543 shifted.push_back (moved_note);
2548 }
else if (!to_play.empty()) {
2551 moved_note->
set_note (moved_note->
note() + cumulative_dy);
2560 uint8_t lowest_note_in_selection = 127;
2561 uint8_t highest_note_in_selection = 0;
2562 uint8_t highest_note_difference = 0;
2567 uint8_t pitch = (*i)->note()->note();
2568 lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
2569 highest_note_in_selection = std::max(highest_note_in_selection, pitch);
2583 if (highest_note_in_selection + dnote > 127) {
2584 highest_note_difference = highest_note_in_selection - 127;
2600 uint8_t original_pitch = (*i)->note()->note();
2601 uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
2606 lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
2607 highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
2694 Note *note =
dynamic_cast<Note*
> (*i);
2699 resize_data->
note = note;
2702 ArdourCanvas::Rectangle *resize_rect =
new ArdourCanvas::Rectangle (
_note_group,
2703 ArdourCanvas::Rect (note->
x0(), note->
y0(), note->
x0(), note->
y1()));
2740 bool cursor_set =
false;
2743 ArdourCanvas::Rectangle* resize_rect = (*i)->resize_rect;
2749 current_x = canvas_note->
x0() + delta_x;
2751 current_x = primary->
x0() + delta_x;
2755 current_x = canvas_note->
x1() + delta_x;
2757 current_x = primary->
x1() + delta_x;
2761 if (current_x < 0) {
2772 resize_rect->set_x1 (canvas_note->
x1());
2775 resize_rect->set_x0 (canvas_note->
x0());
2784 if (beats < canvas_note->note()->end_time()) {
2785 len = canvas_note->
note()->time() - beats;
2786 len += canvas_note->
note()->length();
2789 if (beats >= canvas_note->
note()->time()) {
2790 len = beats - canvas_note->
note()->time();
2797 snprintf (buf,
sizeof (buf),
"%.3g beats", len.
to_double());
2817 ArdourCanvas::Rectangle* resize_rect = (*i)->resize_rect;
2827 current_x = canvas_note->
x0() + delta_x;
2829 current_x = primary->
x0() + delta_x;
2833 current_x = canvas_note->
x1() + delta_x;
2835 current_x = primary->
x1() + delta_x;
2839 if (current_x < 0) {
2852 if (at_front && x_beats < canvas_note->note()->end_time()) {
2856 len += canvas_note->
note()->length();
2865 x_beats - canvas_note->
note()->time());
2881 delete (*i)->resize_rect;
2891 uint8_t new_velocity;
2894 new_velocity =
event->note()->velocity() + velocity;
2897 new_velocity = velocity;
2900 event->set_selected (event->
selected());
2911 new_note =
event->note()->note() + note;
2923 bool change_start =
false;
2924 bool change_length =
false;
2937 if (!!front_delta) {
2938 if (front_delta < 0) {
2940 if (event->
note()->time() < -front_delta) {
2943 new_start =
event->note()->time() + front_delta;
2950 new_length =
event->note()->length() - front_delta;
2951 change_start =
true;
2952 change_length =
true;
2956 Evoral::Beats new_pos =
event->note()->time() + front_delta;
2958 if (new_pos < event->note()->end_time()) {
2959 new_start =
event->note()->time() + front_delta;
2961 new_length =
event->note()->length() - front_delta;
2962 change_start =
true;
2963 change_length =
true;
2970 bool can_change =
true;
2971 if (end_delta < 0) {
2972 if (event->
note()->length() < -end_delta) {
2978 new_length =
event->note()->length() + end_delta;
2979 change_length =
true;
2987 if (change_length) {
2995 uint8_t new_channel;
2999 if (event->
note()->channel() < -chn) {
3002 new_channel =
event->note()->channel() + chn;
3005 new_channel =
event->note()->channel() + chn;
3008 new_channel = (uint8_t) chn;
3021 if (event->
note()->time() < -delta) {
3024 new_time =
event->note()->time() + delta;
3027 new_time =
event->note()->time() + delta;
3064 if ((*i)->note()->velocity() < -delta || (*i)->note()->velocity() + delta > 127) {
3073 Selection::iterator next = i;
3079 value = (*i)->note()->velocity() + delta;
3096 snprintf (buf,
sizeof (buf),
"Vel %d",
3097 (
int) (*
_selection.begin())->note()->velocity());
3125 if ((int8_t) (*i)->note()->note() + delta <= 0) {
3129 if ((int8_t) (*i)->note()->note() + delta > 127) {
3139 Selection::iterator next = i;
3167 Selection::iterator next = i;
3221 if (next_pos == 0) {
3228 const framecnt_t distance = ref_point - next_pos;
3243 Selection::iterator next = i;
3284 (*i)->hide_velocity ();
3297 <<
_(
"Channel ") << ((int) p->
patch()->channel() + 1);
3299 p->
item().grab_focus();
3319 p->
item().grab_focus();
3336 bool trimmable = (mm == MouseContent || mm == MouseTimeFX || mm == MouseDraw);
3339 if (can_set_cursor && ctx) {
3340 if (trimmable && x_fraction > 0.0 && x_fraction < 0.2) {
3342 }
else if (trimmable && x_fraction >= 0.8 && x_fraction < 1.0) {
3353 const std::string mod_name = (
_dragging ?
"dragging region" :
3377 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
3378 (*i)->on_channel_selection_change (mask);
3452 bool commit =
false;
3454 MidiNoteSelection::const_iterator m = selection.midi_notes.get_nth(ctx.
counts.
n_notes());
3455 if (m != selection.midi_notes.end()) {
3457 if (!(*m)->empty()) { commit =
true; }
3464 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
3465 if (a->second->paste(pos, selection, ctx)) {
3491 const Evoral::Beats paste_offset = snap_duration * paste_count;
3503 for (
int n = 0; n < (int) times; ++n) {
3505 for (Notes::const_iterator i = mcb.
notes().begin(); i != mcb.
notes().end(); ++i) {
3508 copied_note->set_time (pos_beats + copied_note->time() - first_time);
3513 end_point = copied_note->end_time();
3522 if (end_frame > region_end) {
3536 return a->
note()->time() < b->
note()->time();
3556 bool use_next =
false;
3558 if (
_events.back()->selected()) {
3567 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
3568 if ((*i)->selected()) {
3571 }
else if (use_next) {
3572 if (channel_mask & (1 << (*i)->note()->channel())) {
3573 if (!add_to_selection) {
3585 if (!
_events.empty() && (channel_mask & (1 <<
_events.front()->note()->channel ()))) {
3593 bool use_next =
false;
3595 if (
_events.front()->selected()) {
3604 for (Events::reverse_iterator i =
_events.rbegin(); i !=
_events.rend(); ++i) {
3605 if ((*i)->selected()) {
3608 }
else if (use_next) {
3609 if (channel_mask & (1 << (*i)->note()->channel())) {
3610 if (!add_to_selection) {
3622 if (!
_events.empty() && (channel_mask & (1 << (*
_events.rbegin())->note()->channel ()))) {
3630 bool had_selected =
false;
3634 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
3635 if ((*i)->selected()) {
3636 selected.insert ((*i)->note());
3637 had_selected =
true;
3641 if (allow_all_if_none_selected && !had_selected) {
3642 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
3643 selected.insert ((*i)->note());
3651 x = std::max(0.0, x);
3737 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
3739 }
else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
3745 bool add_mrv_selection =
false;
3748 add_mrv_selection =
true;
3751 for (Events::iterator i = e.begin(); i != e.end(); ++i) {
3753 (*i)->set_selected (
true);
3757 if (add_mrv_selection) {
3759 editor.get_selection().add (
this);
3768 for (Events::iterator i =
_events.begin(); i !=
_events.end(); ++i) {
3769 (*i)->set_selected ((*i)->selected());
3843 if (!src || src !=
midi_region()->midi_source()) {
3921 int response = d.run();
3924 case Gtk::RESPONSE_ACCEPT:
3926 case Gtk::RESPONSE_REJECT:
3960 MIDI::Name::PatchPrimaryKey patch_key;
3962 name = device_names->note_name(mtv->
gui_property(
X_(
"midnam-custom-device-mode")),
3965 patch_key.program(),
3971 snprintf (buf,
sizeof (buf),
"%d %s\nCh %d Vel %d",
3974 (int) n->channel() + 1,
3975 (int) n->velocity());
3998 return (*m)->velocity();
4002 return (*m)->velocity();
4006 MidiModel::Notes::const_iterator n = m;
4009 const double frac = ((time - (*n)->time()).to_double() /
4010 ((*m)->time() - (*n)->time()).to_double());
4012 return (*n)->velocity() + (frac * ((*m)->velocity() - (*n)->velocity()));
4031 if (editor.
snap_mode() == SnapNormal && p >= grid_frames / 2) {
4032 p -= grid_frames / 2;
4071 bool success =
false;
void change(Gdk::Cursor *cursor)
std::set< boost::shared_ptr< NoteType > > _pending_note_selection
LIBEVORAL_API std::string midi_note_name(uint8_t noteval)
MidiTimeAxisView * midi_view() const
PBD::ScopedConnection _clear_midi_selection_connection
void note_mouse_position(float xfraction, float yfraction, bool can_set_cursor=true)
static sigc::signal< void > DropDownKeys
void sysex_entered(SysEx *p)
void delete_sysex(SysEx *)
void set_duration(double units)
void patch_left(PatchChange *)
void add_note(NoteBase *)
ArdourCanvas::Item * get_canvas_group()
PBD::ScopedConnection content_connection
void delete_patch_change(PatchChange *)
ARDOUR::MidiModel::NoteDiffCommand * _note_diff_command
void apply_command(Session &session, Command *cmd)
void remove_from_selection(NoteBase *)
MIDI::Name::PatchPrimaryKey patch_change_to_patch_key(ARDOUR::MidiModel::PatchChangePtr)
void remove_note(NoteBase *)
void midi_channel_mode_changed()
virtual ArdourCanvas::Coord x1() const =0
Force all events to a certain channel.
static PBD::Signal1< void, RegionView * > RegionViewGoingAway
void get_patch_key_at(Evoral::Beats time, uint8_t channel, MIDI::Name::PatchPrimaryKey &key) const
#define MIDI_CMD_NOTE_OFF
boost::shared_ptr< ARDOUR::MidiModel > _model
bool high_enough_for_name
boost::shared_ptr< ARDOUR::MidiTrack > midi_track() const
bool leave_notify(GdkEventCrossing *)
void set_y0(ArdourCanvas::Coord)
void set_offset(ArdourCanvas::Duple const &)
void set_y1(ArdourCanvas::Coord)
virtual void region_resized(const PBD::PropertyChange &)
PublicEditor & editor() const
void note_left(NoteBase *ev)
static uint32_t calculate_outline(uint32_t color, bool selected=false)
calculate outline colors from fill colors of notes
void get_events(Events &e, Evoral::Sequence< Evoral::Beats >::NoteOperator op, uint8_t val, int chan_mask=0)
PBD::Signal0< void > ChannelModeChanged
void change_channel(PatchChangePtr, uint8_t)
void update_drag_selection(framepos_t start, framepos_t end, double y0, double y1, bool extend)
static void clamp_to_0_127(uint8_t &val)
boost::shared_ptr< ARDOUR::Region > _region
bool operator()(NoteBase *a, NoteBase *b)
PatchChanges _patch_changes
virtual Editing::MouseMode current_mouse_mode() const =0
uint8_t _current_range_max
LIBEVORAL_API const Beats MaxBeats
std::string gui_property(const std::string &property_name) const
LIBEVORAL_API uint64_t Note
Events::iterator _optimization_iterator
static PBD::Signal1< void, NoteBase * > NoteBaseDeleted
virtual ArdourCanvas::Coord x0() const =0
void clear_selection_except(NoteBase *ev, bool signal=true)
void trim_note(NoteBase *ev, ARDOUR::MidiModel::TimeType start_delta, ARDOUR::MidiModel::TimeType end_delta)
void change_note_lengths(bool, bool, Evoral::Beats beats, bool start, bool end)
void update_ghost_note(double, double)
std::string get_patch_name(uint16_t bank, uint8_t program, uint8_t channel) const
bool is_channel_event() const
ARDOUR::BeatsFramesConverter _region_relative_time_converter
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
void update_sustained(Note *, bool update_ghost_regions=true)
void selection_cleared(MidiRegionView *)
bool scroll(GdkEventScroll *)
void change_time(PatchChangePtr, TimeType)
virtual void color_handler()
void update_note(NoteBase *)
bool _enable_display
see StreamView::redisplay_diskstream()
void create_note_at(framepos_t t, double y, Evoral::Beats length, bool snap_t)
void change_note_channel(NoteBase *, int8_t, bool relative=false)
MidiRegionView(ArdourCanvas::Container *parent, RouteTimeAxisView &tv, boost::shared_ptr< ARDOUR::MidiRegion > r, double samples_per_pixel, uint32_t basic_color)
void add_command(Command *const cmd)
framepos_t source_beats_to_region_frames(Evoral::Beats beats) const
static bool patch_applies(const ARDOUR::MidiModel::constPatchChangePtr pc, Evoral::Beats time, uint8_t channel)
Return true iff pc applies to the given time on the given channel.
Evoral::Beats _step_edit_cursor_width
Always round up, even if on a division.
virtual void set_outline_color(uint32_t c)=0
PBD::Signal0< void > Changed
Representation of the interface of the Editor class.
void create_ghost_note(double, double)
void set_fill_color(uint32_t)
std::string fill_color_name
boost::shared_ptr< MidiBuffer > get_gui_feed_buffer() const
Evoral::Sequence< Evoral::Beats >::Notes Notes
framecnt_t _last_display_zoom
void sysex_left(SysEx *p)
virtual std::string get_item_name() const
virtual double sample_to_pixel(framepos_t frame) const =0
void goto_next_note(bool add_to_selection)
ArdourCanvas::Text * name_text
ARDOUR::InstrumentInfo & instrument_info() const
Gdk::Cursor * grabber_note
void mouse_mode_changed()
void display_patch_changes()
const AutomationTracks & automation_tracks() const
void step_sustain(Evoral::Beats beats)
bool key_release(GdkEventKey *)
uint16_t get_playback_channel_mask() const
PBD::Signal0< void > ContentsChanged
Evoral::Beats get_grid_beats(framepos_t pos) const
void unique_select(NoteBase *ev)
void change_bank(PatchChangePtr, int)
void add(boost::shared_ptr< NoteType >)
void note_entered(NoteBase *ev)
Evoral::Beats region_frames_to_region_beats(framepos_t) const
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
bool enter_notify(GdkEventCrossing *)
std::vector< NoteResizeData * > _resize_data
void transpose(bool up, bool fine, bool allow_smush)
uint32_t current_height() const
framecnt_t frame_rate() const
virtual Evoral::Beats get_grid_type_as_beats(bool &success, framepos_t position)=0
double y_position() const
MidiChannelFilter & playback_filter()
bool empty(bool internal_selection=false)
uint8_t lowest_note() const
ArdourCanvas::Item & item() const
void cut_copy_clear(Editing::CutCopyOp)
framepos_t source_beats_to_absolute_frames(Evoral::Beats beats) const
void trim_front_starting()
ArdourCanvas::Rectangle * resize_rect
#define UINT_RGBA_CHANGE_A(x, a)
virtual VerboseCursor * verbose_cursor() const =0
void change_note_velocity(NoteBase *ev, int8_t vel, bool relative=false)
const Meter & meter_at(framepos_t) const
MidiStreamView * midi_stream_view() const
static Handle create(Editor &editor, Gdk::Cursor *cursor)
void reset_width_dependent_items(double pixel_width)
MidiModel::NoteDiffCommand * new_note_diff_command(const std::string name="midi edit")
void change_patch_change(PatchChange &old_patch, const MIDI::Name::PatchPrimaryKey &new_patch)
framepos_t snap_pixel_to_sample(double x)
NoteBase * add_note(const boost::shared_ptr< NoteType > note, bool visible)
void note_selected(NoteBase *ev, bool add, bool extend=false)
uint16_t get_selected_channels() const
bool adds_or_removes() const
PatchChanges & patch_changes()
virtual void enable_display(bool yn)
uint8_t get_channel_for_add() const
void add(std::list< Selectable * > const &)
virtual void snap_to(framepos_t &first, ARDOUR::RoundMode direction=ARDOUR::RoundNearest, bool for_mark=false)=0
MidiListEditor * _list_editor
bool motion(GdkEventMotion *)
LIBGTKMM2EXT_API uint64_t Keyboard
void start_playing_midi_note(boost::shared_ptr< NoteType > note)
void select_range(framepos_t start, framepos_t end)
bool canvas_group_event(GdkEvent *)
void update_hit(Hit *, bool update_ghost_regions=true)
void set_outline_what(ArdourCanvas::Rectangle::What)
virtual DragManager * drags() const =0
LIBARDOUR_API RCConfiguration * Config
Gdk::Cursor * midi_pencil
ARDOUR::ChannelMode get_channel_mode() const
void change_note_time(NoteBase *ev, ARDOUR::MidiModel::TimeType, bool relative=false)
virtual Editing::SnapMode snap_mode() const =0
boost::shared_ptr< ARDOUR::Region > region() const
void show_step_edit_cursor(Evoral::Beats pos)
void show_verbose_cursor(std::string const &, double, double) const
bool _mouse_changed_selection
uint64_t to_ticks() const
virtual framecnt_t get_current_zoom() const =0
void note_deselected(NoteBase *ev)
const boost::shared_ptr< ARDOUR::MidiRegion > midi_region() const
void get_notes(Notes &, NoteOperator, uint8_t val, int chan_mask=0) const
void selection_as_notelist(Notes &selected, bool allow_all_if_none_selected=false)
void toggle_matching_notes(uint8_t notenum, uint16_t channel_mask)
Editing::MouseMode current_mouse_mode() const
virtual void init(bool wait_for_data)
void set_position(ArdourCanvas::Duple)
void check_record_layers(boost::shared_ptr< ARDOUR::Region >, ARDOUR::framepos_t)
void delete_note(boost::shared_ptr< NoteType >)
void display_model(boost::shared_ptr< ARDOUR::MidiModel > model)
boost::shared_ptr< CursorContext > _press_cursor_ctx
void set_fill_color(uint32_t)
framepos_t region_beats_to_region_frames(Evoral::Beats beats) const
bool note_in_region_range(const boost::shared_ptr< NoteType > note, bool &visible) const
ARDOUR::frameoffset_t snap_frame_to_frame(ARDOUR::frameoffset_t) const
void parameter_changed(std::string const &p)
framecnt_t get_duration() const
ARDOUR::Session * session() const
ARDOUR::BeatsFramesConverter _source_relative_time_converter
virtual void begin_reversible_command(std::string cmd_name)=0
virtual void set_frame_color()
void extend_active_notes()
void update_vertical_drag_selection(double last_y, double y, bool extend)
virtual void commit_reversible_command()=0
static uint32_t meter_style_fill_color(uint8_t vel, bool selected)
void change(const NotePtr note, Property prop, uint8_t new_value)
void set(Drag *, GdkEvent *, Gdk::Cursor *c=MouseCursors::invalid_cursor())
Gdk::Cursor * right_side_trim
void maybe_remove_deleted_note_from_selection(NoteBase *)
void apply_command_as_subcommand(Session &session, Command *cmd)
ARDOUR::MidiModel::PatchChangePtr patch() const
void step_patch(PatchChange &patch, bool bank, int delta)
virtual ReadLock read_lock() const
void swap(shared_ptr< T > &a, shared_ptr< T > &b)
void update_note_range(uint8_t note_num)
MouseCursors const * cursors() const
PBD::Signal0< void > SnapChanged
#define DEBUG_TRACE(bits, str)
Evoral::Beats from(framepos_t frames) const
ArdourCanvas::Container * _note_group
bool motion_handler(GdkEvent *, bool)
void set_selected(bool yn)
PBD::ScopedConnection snap_changed_connection
ArdourCanvas::Rectangle * frame_handle_start
`frame' (fade) handle for the start of the item, or 0
virtual Selection & get_selection() const =0
VerboseCursor * verbose_cursor() const
void instrument_settings_changed()
EnterContext * get_enter_context(ItemType type)
shared_ptr< T > static_pointer_cast(shared_ptr< U > const &r)
PBD::ScopedConnection _instrument_changed_connection
virtual void region_muted()
Beats snap_to(const Evoral::Beats &snap) const
MidiCutBuffer * selection_as_cut_buffer() const
void move_step_edit_cursor(Evoral::Beats pos)
double get_end_position_pixels()
void set_outline_color(uint32_t)
ArdourCanvas::Coord y1() const
void update_resizing(NoteBase *, bool, double, bool)
virtual void reset_width_dependent_items(double pixel_width)
void patch_entered(PatchChange *)
PBD::Signal1< void, std::string > ParameterChanged
virtual double height() const
uint8_t _current_range_min
ArdourCanvas::Container * _temporary_note_group
void display_patch_changes_on_channel(uint8_t, bool)
void set_x0(ArdourCanvas::Coord)
void region_resized(const PBD::PropertyChange &)
void set(const Evoral::Sequence< TimeType >::Notes &)
NoteBase * find_canvas_note(boost::shared_ptr< NoteType >)
ItemCounts counts
Count of consumed selection items.
uint8_t get_velocity_for_add(ARDOUR::MidiModel::TimeType time) const
framepos_t position() const
void set_step_edit_cursor_width(Evoral::Beats beats)
void apply_note_range(uint8_t lowest, uint8_t highest, bool to_region_views)
void maybe_select_by_position(GdkEventButton *ev, double x, double y)
void remove_ghost(GhostRegion *)
void connect_to_diskstream()
void change_note_length(NoteBase *, ARDOUR::MidiModel::TimeType)
void hide_step_edit_cursor()
const boost::shared_ptr< NoteType > note() const
void play_midi_note(boost::shared_ptr< NoteType > note)
void clear_midi_selection()
void add_canvas_patch_change(ARDOUR::MidiModel::PatchChangePtr patch, const std::string &displaytext, bool)
PatchChanges::const_iterator patch_change_lower_bound(Time t) const
double snap_to_pixel(double x)
PBD::ScopedConnection _mouse_mode_connection
virtual bool set_duration(framecnt_t, void *)
std::set< boost::shared_ptr< NoteType > > _marked_for_velocity
virtual bool internal_editing() const =0
void commit_resizing(NoteBase *, bool, double, bool)
void step_add_note(uint8_t channel, uint8_t number, uint8_t velocity, Evoral::Beats pos, Evoral::Beats len)
void paste_internal(framepos_t pos, unsigned paste_count, float times, const MidiCutBuffer &)
MidiModel::PatchChangeDiffCommand * new_patch_change_diff_command(const std::string name="midi edit")
framepos_t snap_frame_to_grid_underneath(framepos_t p, framecnt_t &) const
uint8_t active_channel() const
void change_channel(uint8_t channel)
LIBARDOUR_API PBD::PropertyDescriptor< bool > relative
ArdourCanvas::Rectangle * frame
virtual void set_height(double)
boost::shared_ptr< CursorContext > cursor_ctx
void select_matching_notes(uint8_t notenum, uint16_t channel_mask, bool add, bool extend)
void enable_display(bool)
PBD::Signal1< void, boost::weak_ptr< MidiSource > > DataRecorded
void move_patch_change(PatchChange &, Evoral::Beats)
bool button_press(GdkEventButton *)
virtual void set_ignore_events(bool ignore)=0
void set_length(framecnt_t)
ArdourCanvas::Color color_mod(std::string const &color, std::string const &modifier) const
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
void note_diff_remove_note(NoteBase *ev)
static UIConfiguration * config()
void start_playing_midi_chord(std::vector< boost::shared_ptr< NoteType > > notes)
std::vector< GhostRegion * > ghosts
void change_velocities(bool up, bool fine, bool allow_smush, bool all_together)
uint32_t get_fill_color() const
void move_selection(double dx, double dy, double cumulative_dy)
void update_note(NoteBase *, bool update_ghost_regions=true)
void change_note_note(NoteBase *ev, int8_t note, bool relative=false)
ArdourCanvas::Coord x0() const
bool key_press(GdkEventKey *)
void set_note_range(VisibleNoteRange r)
uint8_t highest_note() const
LIBARDOUR_API PBD::PropertyDescriptor< bool > select
void change_program(PatchChangePtr, uint8_t)
uint8_t y_to_note(double y) const
double divisions_per_bar() const
GhostRegion * add_ghost(TimeAxisView &)
framepos_t timeline_position() const
ArdourCanvas::Rectangle * frame_handle_end
`frame' (fade) handle for the end of the item, or 0
float times
Number of times to paste.
void remove(const NotePtr note)
virtual framepos_t pixel_to_sample(double pixel) const =0
ArdourCanvas::Item & item() const
bool button_release(GdkEventButton *)
bool contains(const NotePtr &ev) const
std::set< boost::shared_ptr< NoteType > > _marked_for_selection
void set_x1(ArdourCanvas::Coord)
bool paste(framepos_t pos, const ::Selection &selection, PasteContext &ctx)
LIBEVORAL_API uint64_t Beats
ArdourCanvas::Container * group
bool contains(PropertyDescriptor< T > p) const
void set_outline_color(uint32_t)
PBD::ScopedConnection note_delete_connection
std::map< Evoral::Parameter, boost::shared_ptr< AutomationTimeAxisView > > AutomationTracks
void note_dropped(NoteBase *ev, ARDOUR::frameoffset_t, int8_t d_note)
framecnt_t length() const
static const framepos_t max_framepos
void region_sync_changed()
InstrumentInfo & instrument_info()
void add_to_selection(NoteBase *)
void goto_previous_note(bool add_to_selection)
static PBD::Signal1< void, MidiRegionView * > SelectionCleared
static double note_height(TimeAxisView &trackview, MidiStreamView *mv)
boost::shared_ptr< MidiSource > midi_source(uint32_t n=0) const
void fix_negative_start()
ChannelMode get_playback_channel_mode() const
ArdourCanvas::Coord x1() const
void set(std::string const &)
#define UINT_INTERPOLATE(c1, c2, t)
void note_diff_add_change(NoteBase *ev, ARDOUR::MidiModel::NoteDiffCommand::Property, uint8_t val)
ArdourCanvas::Coord y0() const
void apply_diff(bool as_subcommand=false)
#define RGBA_TO_UINT(r, g, b, a)
LIBGTKMM2EXT_API int pixel_width(const std::string &str, Pango::FontDescription &font)
void select_notes(std::list< boost::shared_ptr< NoteType > >)
framepos_t to(Evoral::Beats beats) const
virtual void begin_reversible_selection_op(std::string cmd_name)=0
void resolve_note(uint8_t note_num, Evoral::Beats end_time)
void increase_n_notes(size_t delta=1)
void nudge_notes(bool forward, bool fine)
void start_note_diff_command(std::string name="midi edit")
Gdk::Cursor * left_side_trim
boost::shared_ptr< MIDI::Name::MasterDeviceNames > get_device_names()
double contents_height() const
unsigned count
Number of previous pastes to the same position.
void clear_events(bool with_selection_signal=true)
Notes::const_iterator note_lower_bound(Time t) const
framepos_t get_position() const
#define MISSING_INVALIDATOR
double get_position_pixels()
Evoral::Beats _step_edit_cursor_position
void begin_resizing(bool at_front)
static PBD::Signal1< void, GhostRegion * > CatchDeletion
void data_recorded(boost::weak_ptr< ARDOUR::MidiSource >)
std::list< NoteBase * > Events
PBD::Signal0< void > MouseModeChanged
void set_height(ArdourCanvas::Coord)
void edit_patch_change(PatchChange *)
void remove(PatchChangePtr)
PBD::ScopedConnection _selection_cleared_connection
boost::shared_ptr< ARDOUR::Route > route() const
MidiStreamView * midi_view()
virtual void set_colors()
Always round down, even if on a division.
void note_diff_add_note(const boost::shared_ptr< NoteType > note, bool selected, bool show_velocity=false)
bool canvas_group_event(GdkEvent *ev)
PBD::ScopedConnection _channel_mode_changed_connection
boost::shared_ptr< MidiPlaylist > midi_playlist()
bool end_grab(GdkEvent *)
void add(const NotePtr note)
LIBARDOUR_API PBD::PropertyChange bounds_change
std::string string_compose(const std::string &fmt, const T1 &o1)
void add_patch_change(framecnt_t, Evoral::PatchChange< Evoral::Beats > const &)
Ignore events on certain channels.
virtual void commit_reversible_selection_op()=0
Evoral::Beats absolute_frames_to_source_beats(framepos_t) const
void clear_selection(bool signal=true)
framepos_t last_frame() const
virtual framecnt_t get_nudge_distance(framepos_t pos, framecnt_t &next)=0
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
ArdourCanvas::Rectangle * _step_edit_cursor
LIBARDOUR_API PBD::PropertyDescriptor< bool > color
void apply_note_range(uint8_t lowest, uint8_t highest, bool force=false)