View Issue Details

IDProjectCategoryView StatusLast Update
0002148ardourfeaturespublic2008-04-14 12:40
Reporterhansfbaier Assigned To 
PrioritynormalSeverityfeatureReproducibilityalways
Status closedResolutionfixed 
PlatformLinux Ubuntu studio gutsyOSLinuxOS Version 2.6.22-14-rt
Summary0002148: Implemented Editing velocities, please apply patch
DescriptionEditing velocities of single notes or groups of notes is
now possible by using the mouse wheel over the notes or selections.
Contained in the patch are several bugfixes in MidiRegionView
and an improvement of its selection model.
TagsNo tags attached.

Activities

2008-03-28 05:21

 

implemented_editing_velocities_and_improved_selection_model_and_bugfixes_midi_region_view.diff (10,001 bytes)   
Index: gtk2_ardour/editor_canvas_events.cc
===================================================================
--- gtk2_ardour/editor_canvas_events.cc	(Revision 3194)
+++ gtk2_ardour/editor_canvas_events.cc	(Arbeitskopie)
@@ -40,6 +40,7 @@
 #include "control_point.h"
 #include "canvas_impl.h"
 #include "simplerect.h"
+#include "canvas-midi-event.h"
 
 #include "i18n.h"
 
@@ -48,6 +49,7 @@
 using namespace ARDOUR;
 using namespace PBD;
 using namespace Gtk;
+using namespace ArdourCanvas;
 
 bool
 Editor::track_canvas_scroll (GdkEventScroll* ev)
@@ -56,6 +58,7 @@
 	double wx, wy;
 	nframes_t xdelta;
 	int direction = ev->direction;
+	CanvasMidiEvent *midi_event = dynamic_cast<CanvasMidiEvent *>(track_canvas->get_item_at(ev->x, ev->y));
 
   retry:
 	switch (direction) {
@@ -94,6 +97,9 @@
 			current_stepping_trackview->step_height (true);
 			return true;
 		} else {
+			if(midi_event) {
+				return midi_event->on_event(reinterpret_cast<GdkEvent *>(ev));
+			}
 			scroll_tracks_up_line ();
 			return true;
 		}
@@ -129,6 +135,9 @@
 			current_stepping_trackview->step_height (false);
 			return true;
 		} else {
+			if(midi_event) {
+				return midi_event->on_event(reinterpret_cast<GdkEvent *>(ev));
+			}
 			scroll_tracks_down_line ();
 			return true;
 		}
Index: gtk2_ardour/midi_util.h
===================================================================
--- gtk2_ardour/midi_util.h	(Revision 3194)
+++ gtk2_ardour/midi_util.h	(Arbeitskopie)
@@ -54,5 +54,14 @@
 	}
 }
 
+inline static void clamp_0_to_127(uint8_t &val)
+{
+	if( (127 < val) && (val < 192) ) {
+		val = 127;
+	} else if( (192 <= val) && (val < 255) ) {
+		val = 0;
+	} 
+}
+
 #endif /* __gtk_ardour_midi_util_h__ */
 
Index: gtk2_ardour/canvas-midi-event.cc
===================================================================
--- gtk2_ardour/canvas-midi-event.cc	(Revision 3194)
+++ gtk2_ardour/canvas-midi-event.cc	(Arbeitskopie)
@@ -49,7 +49,7 @@
 		return;
 	} else if (yn) {
 		set_fill_color(UINT_INTERPOLATE(note_fill_color(_note->velocity()),
-					ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(), 0.85));
+					ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(), 0.1));
 		set_outline_color(ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get());
 	} else {
 		set_fill_color(note_fill_color(_note->velocity()));
@@ -75,6 +75,27 @@
 		return false;
 
 	switch (ev->type) {
+	case GDK_SCROLL:
+		if(ev->scroll.direction == GDK_SCROLL_UP) {
+			_region.note_selected(this, true);
+			if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) {
+				// TODO: absolute velocity
+			} else {
+				_region.change_velocity(10, true);
+			}
+			return true;
+		} else if(ev->scroll.direction == GDK_SCROLL_DOWN) {
+			_region.note_selected(this, true);
+			if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) {
+				// TODO: absolute velocity
+			} else {
+				_region.change_velocity(-10, true);
+			}
+			return true;
+		} else {
+			return false;
+		}
+		
 	case GDK_KEY_PRESS:
 		if (_note && ev->key.keyval == GDK_Delete) {
 			selected(true);
Index: gtk2_ardour/midi_region_view.h
===================================================================
--- gtk2_ardour/midi_region_view.h	(Revision 3194)
+++ gtk2_ardour/midi_region_view.h	(Arbeitskopie)
@@ -103,6 +103,7 @@
 
 	void command_remove_note(ArdourCanvas::CanvasMidiEvent* ev) {
 		if (_delta_command && ev->note()) {
+			_selection.erase(ev);
 			_delta_command->remove(ev->note());
 			ev->selected(true);
 		}
@@ -162,6 +163,14 @@
 	 */
 	void commit_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end, double event_x, bool relative);
 
+	/**
+	 * This function is called while the user adjusts the velocity on a selection of notes
+	 * @param velocity the relative or absolute velocity, dependin on the value of relative
+	 * @param relative true if the given velocity represents a delta to be applied to all notes, false
+	 *        if the absolute value of the note shoud be set
+	 */
+	void change_velocity(uint8_t velocity, bool relative=false);
+
 	enum MouseState { None, Pressed, SelectTouchDragging, SelectRectDragging, AddDragging, EraseTouchDragging };
 	MouseState mouse_state() const { return _mouse_state; }
 
@@ -221,9 +230,17 @@
 	MouseState _mouse_state;
 	int _pressed_button;
 
+	/// currently selected CanvasMidiEvents
 	typedef std::set<ArdourCanvas::CanvasMidiEvent*> Selection;
 	Selection _selection;
 
+	/**
+	 * this enables vanilla notes to be marked for selection
+	 * they are added to _selection when redisplay_model is called
+	 * this is necessary for selecting notes during/after model manipulations 
+	 */
+	std::set<ARDOUR::Note *> _marked_for_selection;
+
 	std::vector<NoteResizeData *> _resize_data;
 };
 
Index: gtk2_ardour/midi_region_view.cc
===================================================================
--- gtk2_ardour/midi_region_view.cc	(Revision 3194)
+++ gtk2_ardour/midi_region_view.cc	(Arbeitskopie)
@@ -423,8 +423,22 @@
 
 		_model->read_lock();
 
-		for (size_t i=0; i < _model->n_notes(); ++i)
+		/*
+		MidiModel::Notes notes = _model->notes();
+		cerr << endl << "Model contains " << notes.size() << " Notes:" << endl;
+		for(MidiModel::Notes::iterator i = notes.begin(); i != notes.end(); ++i) {
+			Note note = *(*i).get();
+			cerr << "MODEL: Note time: " << note.time() << " duration: " << note.duration() 
+			     << "   end-time: " << note.end_time() 
+			     << "   velocity: " << int(note.velocity()) 
+			     //<< " Note-on: " << note.on_event(). 
+			     //<< " Note-off: " << note.off_event() 
+			     << endl;
+		}*/
+		
+		for (size_t i=0; i < _model->n_notes(); ++i) {
 			add_note(_model->note_at(i));
+		}
 
 		end_write();
 
@@ -609,6 +623,7 @@
 {
 	delete[] _active_notes;
 	_active_notes = NULL;
+	_marked_for_selection.clear();
 }
 
 
@@ -657,6 +672,8 @@
 
 	ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
 
+	CanvasMidiEvent *event = 0;
+	
 	if (midi_view()->note_mode() == Sustained) {
 
 		//cerr << "MRV::add_note sustained " << note->note() << " @ " << note->time()
@@ -687,6 +704,7 @@
 
 		ev_rect->show();
 		_events.push_back(ev_rect);
+		event = ev_rect;
 
 		MidiGhostRegion* gr;
 
@@ -711,9 +729,19 @@
 		ev_diamond->property_fill_color_rgba() = note_fill_color(note->velocity());
 		ev_diamond->property_outline_color_rgba() = note_outline_color(note->velocity());
 		_events.push_back(ev_diamond);
+		event = ev_diamond;
+	} else {
+		event = 0;
+	}
 
+	if(event) {
+		Note *note = event->note().get();
+		
+		if(_marked_for_selection.find(note) != _marked_for_selection.end()) {
+			note_selected(event, true);
 	}
 }
+}
 
 void
 MidiRegionView::delete_selection()
@@ -851,7 +879,6 @@
 		// 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();
@@ -868,9 +895,15 @@
 				copy->set_time(0);
 			}
 
-			uint8_t new_pitch = (*i)->note()->note() + dnote - highest_note_difference;
-			if(new_pitch > 127) {
-				new_pitch = 127;
+			uint8_t original_pitch = (*i)->note()->note();
+			uint8_t new_pitch =  original_pitch + dnote - highest_note_difference;
+			
+			// keep notes in standard midi range
+			clamp_0_to_127(new_pitch);
+			
+			//notes which are dragged beyond the standard midi range snap back to their original place
+			if((original_pitch != 0 && new_pitch == 0) || (original_pitch != 127 && new_pitch == 127)) {
+				new_pitch = original_pitch;
 			}
 
 			lowest_note_in_selection  = std::min(lowest_note_in_selection,  new_pitch);
@@ -880,19 +913,16 @@
 			
 			command_add_note(copy);
 
-			_selection.erase(i);
+			_marked_for_selection.insert(copy.get());
 			i = next;
 		}
 				
 		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);
 	}
 }
@@ -1031,12 +1061,15 @@
 			command_remove_note(canvas_note);
 			copy->on_event().time() = current_frame;
 			command_add_note(copy);
+			_marked_for_selection.insert(copy.get());
 		}
 		// resize end of note
 		if (note_end == CanvasNote::NOTE_OFF && current_frame > copy->time()) {
 			command_remove_note(canvas_note);
+			command_remove_note(canvas_note);
 			copy->off_event().time() = current_frame;
 			command_add_note(copy);
+			_marked_for_selection.insert(copy.get());
 		}
 
 		delete resize_rect;
@@ -1045,10 +1078,46 @@
 
 	_resize_data.clear();
 	apply_command();
-	clear_selection();
 }
 
+
 void
+MidiRegionView::change_velocity(uint8_t velocity, bool relative)
+{
+	start_delta_command();
+	for (Selection::iterator i = _selection.begin(); i != _selection.end();) {
+		Selection::iterator next = i;
+		++next;
+
+		CanvasMidiEvent *event = *i;
+		const boost::shared_ptr<Note> copy(new Note(*(event->note().get())));
+
+		if(relative) {
+			uint8_t new_velocity = copy->velocity() + velocity;
+			clamp_0_to_127(new_velocity);
+				
+			copy->set_velocity(new_velocity);
+		} else { // absolute
+			copy->set_velocity(velocity);			
+		}
+		
+		command_remove_note(event);
+		command_add_note(copy);
+		
+		_marked_for_selection.insert(copy.get());
+		i = next;
+	}
+	
+	// dont keep notes selected if tweaking a single note
+	if(_marked_for_selection.size() == 1) {
+		_marked_for_selection.clear();
+	}
+	
+	apply_command();
+}
+
+
+void
 MidiRegionView::note_entered(ArdourCanvas::CanvasMidiEvent* ev)
 {
 	if (ev->note() && _mouse_state == EraseTouchDragging) {

2008-03-31 00:51

 

implemented_editing_velocities_and_bugfixes_midi_region_view.diff (13,676 bytes)   
Index: gtk2_ardour/editor_canvas_events.cc
===================================================================
--- gtk2_ardour/editor_canvas_events.cc	(Revision 3197)
+++ gtk2_ardour/editor_canvas_events.cc	(Arbeitskopie)
@@ -40,6 +40,7 @@
 #include "control_point.h"
 #include "canvas_impl.h"
 #include "simplerect.h"
+#include "canvas-midi-event.h"
 
 #include "i18n.h"
 
@@ -48,6 +49,7 @@
 using namespace ARDOUR;
 using namespace PBD;
 using namespace Gtk;
+using namespace ArdourCanvas;
 
 bool
 Editor::track_canvas_scroll (GdkEventScroll* ev)
@@ -56,6 +58,7 @@
 	double wx, wy;
 	nframes_t xdelta;
 	int direction = ev->direction;
+	CanvasMidiEvent *midi_event = dynamic_cast<CanvasMidiEvent *>(track_canvas->get_item_at(ev->x, ev->y));
 
   retry:
 	switch (direction) {
@@ -94,6 +97,9 @@
 			current_stepping_trackview->step_height (true);
 			return true;
 		} else {
+			if(midi_event) {
+				return midi_event->on_event(reinterpret_cast<GdkEvent *>(ev));
+			}
 			scroll_tracks_up_line ();
 			return true;
 		}
@@ -129,6 +135,9 @@
 			current_stepping_trackview->step_height (false);
 			return true;
 		} else {
+			if(midi_event) {
+				return midi_event->on_event(reinterpret_cast<GdkEvent *>(ev));
+			}
 			scroll_tracks_down_line ();
 			return true;
 		}
Index: gtk2_ardour/midi_util.h
===================================================================
--- gtk2_ardour/midi_util.h	(Revision 3197)
+++ gtk2_ardour/midi_util.h	(Arbeitskopie)
@@ -54,5 +54,14 @@
 	}
 }
 
+inline static void clamp_0_to_127(uint8_t &val)
+{
+	if( (127 < val) && (val < 192) ) {
+		val = 127;
+	} else if( (192 <= val) && (val < 255) ) {
+		val = 0;
+	} 
+}
+
 #endif /* __gtk_ardour_midi_util_h__ */
 
Index: gtk2_ardour/canvas-midi-event.cc
===================================================================
--- gtk2_ardour/canvas-midi-event.cc	(Revision 3197)
+++ gtk2_ardour/canvas-midi-event.cc	(Arbeitskopie)
@@ -35,25 +35,56 @@
 		const boost::shared_ptr<ARDOUR::Note> note)
 	: _region(region)
 	, _item(item)
+	, _text(0)
 	, _state(None)
 	, _note(note)
 	, _selected(false)
 {
+	_text = new Text(*(item->property_parent()));
 }
 
+void 
+CanvasMidiEvent::move_event(double dx, double dy)
+{
+	_item->move(dx, dy);
+	_text->move(dx, dy);
+}
 
 void
+CanvasMidiEvent::show_velocity(void)
+{
+	_text->property_x() = (x1() + x2()) /2;
+	_text->property_y() = (y1() + y2()) /2;
+	ostringstream velo(ios::ate);
+	velo << int(_note->velocity());
+	_text->property_text() = velo.str();
+	_text->property_justification() = Gtk::JUSTIFY_CENTER;
+	_text->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get();
+	_text->show();
+	_text->lower_to_bottom();
+	_text->raise(2);
+}
+
+void
+CanvasMidiEvent::hide_velocity(void)
+{
+	_text->hide();
+}
+
+void
 CanvasMidiEvent::selected(bool yn)
 {
 	if (!_note) {
 		return;
 	} else if (yn) {
 		set_fill_color(UINT_INTERPOLATE(note_fill_color(_note->velocity()),
-					ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(), 0.85));
+					ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(), 0.1));
 		set_outline_color(ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get());
+		show_velocity();
 	} else {
 		set_fill_color(note_fill_color(_note->velocity()));
 		set_outline_color(note_outline_color(_note->velocity()));
+		hide_velocity();
 	}
 
 	_selected = yn;
@@ -70,11 +101,38 @@
 	double event_x, event_y, dx, dy;
 	nframes_t event_frame;
 	bool select_mod;
+	uint8_t d_velocity = 10;
 
 	if (_region.get_time_axis_view().editor.current_mouse_mode() != Editing::MouseNote)
 		return false;
 
 	switch (ev->type) {
+	case GDK_SCROLL:
+		if (Keyboard::modifier_state_equals (ev->scroll.state, Keyboard::Level4Modifier)) {
+			d_velocity = 1;
+		}
+
+		if(ev->scroll.direction == GDK_SCROLL_UP) {
+			_region.note_selected(this, true);
+			if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) {
+				// TODO: absolute velocity
+			} else {
+				_region.change_velocity(d_velocity, true);
+			}
+			return true;
+		} else if(ev->scroll.direction == GDK_SCROLL_DOWN) {
+			
+			_region.note_selected(this, true);
+			if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) {
+				// TODO: absolute velocity
+			} else {
+				_region.change_velocity(-d_velocity, true);
+			}
+			return true;
+		} else {
+			return false;
+		}
+		
 	case GDK_KEY_PRESS:
 		if (_note && ev->key.keyval == GDK_Delete) {
 			selected(true);
@@ -92,11 +150,15 @@
 	case GDK_ENTER_NOTIFY:
 		_region.note_entered(this);
 		_item->grab_focus();
+		show_velocity();
 		Keyboard::magic_widget_grab_focus();
 		break;
 
 	case GDK_LEAVE_NOTIFY:
 		Keyboard::magic_widget_drop_focus();
+		if(! selected()) {
+			hide_velocity();
+		}
 		_region.get_canvas_group()->grab_focus();
 		break;
 
Index: gtk2_ardour/midi_region_view.h
===================================================================
--- gtk2_ardour/midi_region_view.h	(Revision 3197)
+++ gtk2_ardour/midi_region_view.h	(Arbeitskopie)
@@ -103,6 +103,7 @@
 
 	void command_remove_note(ArdourCanvas::CanvasMidiEvent* ev) {
 		if (_delta_command && ev->note()) {
+			_selection.erase(ev);
 			_delta_command->remove(ev->note());
 			ev->selected(true);
 		}
@@ -162,6 +163,14 @@
 	 */
 	void commit_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end, double event_x, bool relative);
 
+	/**
+	 * This function is called while the user adjusts the velocity on a selection of notes
+	 * @param velocity the relative or absolute velocity, dependin on the value of relative
+	 * @param relative true if the given velocity represents a delta to be applied to all notes, false
+	 *        if the absolute value of the note shoud be set
+	 */
+	void change_velocity(uint8_t velocity, bool relative=false);
+
 	enum MouseState { None, Pressed, SelectTouchDragging, SelectRectDragging, AddDragging, EraseTouchDragging };
 	MouseState mouse_state() const { return _mouse_state; }
 
@@ -221,9 +230,17 @@
 	MouseState _mouse_state;
 	int _pressed_button;
 
+	/// currently selected CanvasMidiEvents
 	typedef std::set<ArdourCanvas::CanvasMidiEvent*> Selection;
 	Selection _selection;
 
+	/**
+	 * this enables vanilla notes to be marked for selection
+	 * they are added to _selection when redisplay_model is called
+	 * this is necessary for selecting notes during/after model manipulations 
+	 */
+	std::set<ARDOUR::Note *> _marked_for_selection;
+
 	std::vector<NoteResizeData *> _resize_data;
 };
 
Index: gtk2_ardour/canvas-midi-event.h
===================================================================
--- gtk2_ardour/canvas-midi-event.h	(Revision 3197)
+++ gtk2_ardour/canvas-midi-event.h	(Arbeitskopie)
@@ -21,6 +21,7 @@
 #define __gtk_ardour_canvas_midi_event_h__
 
 #include "simplerect.h"
+#include <libgnomecanvasmm/text.h>
 #include <ardour/midi_model.h>
 
 class Editor;
@@ -48,13 +49,18 @@
 			Item*                                 item,
 			const boost::shared_ptr<ARDOUR::Note> note = boost::shared_ptr<ARDOUR::Note>());
 
-	virtual ~CanvasMidiEvent() {}
+	virtual ~CanvasMidiEvent() { if(_text) delete _text; }
 
 	bool on_event(GdkEvent* ev);
 
 	bool selected() const { return _selected; }
 	void selected(bool yn);
 
+	void move_event(double dx, double dy);
+	
+	void show_velocity();
+	void hide_velocity();
+
 	virtual void set_outline_color(uint32_t c) = 0;
 	virtual void set_fill_color(uint32_t c) = 0;
 	
@@ -63,9 +69,6 @@
 	virtual double x2() = 0;
 	virtual double y2() = 0;
 
-	const Item* item() const { return _item; }
-	Item*       item()       { return _item; }
-
 	const boost::shared_ptr<ARDOUR::Note> note() { return _note; }
 
 protected:
@@ -73,6 +76,7 @@
 
 	MidiRegionView&                       _region;
 	Item* const                           _item;
+	Text* 		                          _text;
 	State                                 _state;
 	const boost::shared_ptr<ARDOUR::Note> _note;
 	bool                                  _own_note;
Index: gtk2_ardour/midi_region_view.cc
===================================================================
--- gtk2_ardour/midi_region_view.cc	(Revision 3197)
+++ gtk2_ardour/midi_region_view.cc	(Arbeitskopie)
@@ -423,8 +423,22 @@
 
 		_model->read_lock();
 
-		for (size_t i=0; i < _model->n_notes(); ++i)
+		/*
+		MidiModel::Notes notes = _model->notes();
+		cerr << endl << "Model contains " << notes.size() << " Notes:" << endl;
+		for(MidiModel::Notes::iterator i = notes.begin(); i != notes.end(); ++i) {
+			Note note = *(*i).get();
+			cerr << "MODEL: Note time: " << note.time() << " duration: " << note.duration() 
+			     << "   end-time: " << note.end_time() 
+			     << "   velocity: " << int(note.velocity()) 
+			     //<< " Note-on: " << note.on_event(). 
+			     //<< " Note-off: " << note.off_event() 
+			     << endl;
+		}*/
+		
+		for (size_t i=0; i < _model->n_notes(); ++i) {
 			add_note(_model->note_at(i));
+		}
 
 		end_write();
 
@@ -538,11 +552,15 @@
 						note->show();
 					}
 
+					note->hide_velocity();
 					note->property_y1() = y1;
 					note->property_y2() = y2;
+					if(note->selected()) {
+						note->show_velocity();
 				}
 			}
 		}
+		}
 
 		_model->read_unlock();
 	}
@@ -609,6 +627,7 @@
 {
 	delete[] _active_notes;
 	_active_notes = NULL;
+	_marked_for_selection.clear();
 }
 
 
@@ -657,6 +676,8 @@
 
 	ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
 
+	CanvasMidiEvent *event = 0;
+	
 	if (midi_view()->note_mode() == Sustained) {
 
 		//cerr << "MRV::add_note sustained " << note->note() << " @ " << note->time()
@@ -687,6 +708,7 @@
 
 		ev_rect->show();
 		_events.push_back(ev_rect);
+		event = ev_rect;
 
 		MidiGhostRegion* gr;
 
@@ -711,9 +733,19 @@
 		ev_diamond->property_fill_color_rgba() = note_fill_color(note->velocity());
 		ev_diamond->property_outline_color_rgba() = note_outline_color(note->velocity());
 		_events.push_back(ev_diamond);
+		event = ev_diamond;
+	} else {
+		event = 0;
+	}
 
+	if(event) {
+		Note *note = event->note().get();
+		
+		if(_marked_for_selection.find(note) != _marked_for_selection.end()) {
+			note_selected(event, true);
 	}
 }
+}
 
 void
 MidiRegionView::delete_selection()
@@ -813,7 +845,7 @@
 MidiRegionView::move_selection(double dx, double dy)
 {
 	for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i)
-		(*i)->item()->move(dx, dy);
+		(*i)->move_event(dx, dy);
 }
 
 
@@ -851,7 +883,6 @@
 		// 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();
@@ -868,9 +899,15 @@
 				copy->set_time(0);
 			}
 
-			uint8_t new_pitch = (*i)->note()->note() + dnote - highest_note_difference;
-			if(new_pitch > 127) {
-				new_pitch = 127;
+			uint8_t original_pitch = (*i)->note()->note();
+			uint8_t new_pitch =  original_pitch + dnote - highest_note_difference;
+			
+			// keep notes in standard midi range
+			clamp_0_to_127(new_pitch);
+			
+			//notes which are dragged beyond the standard midi range snap back to their original place
+			if((original_pitch != 0 && new_pitch == 0) || (original_pitch != 127 && new_pitch == 127)) {
+				new_pitch = original_pitch;
 			}
 
 			lowest_note_in_selection  = std::min(lowest_note_in_selection,  new_pitch);
@@ -880,19 +917,16 @@
 			
 			command_add_note(copy);
 
-			_selection.erase(i);
+			_marked_for_selection.insert(copy.get());
 			i = next;
 		}
 				
 		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);
 	}
 }
@@ -1031,12 +1065,15 @@
 			command_remove_note(canvas_note);
 			copy->on_event().time() = current_frame;
 			command_add_note(copy);
+			_marked_for_selection.insert(copy.get());
 		}
 		// resize end of note
 		if (note_end == CanvasNote::NOTE_OFF && current_frame > copy->time()) {
 			command_remove_note(canvas_note);
+			command_remove_note(canvas_note);
 			copy->off_event().time() = current_frame;
 			command_add_note(copy);
+			_marked_for_selection.insert(copy.get());
 		}
 
 		delete resize_rect;
@@ -1045,10 +1082,46 @@
 
 	_resize_data.clear();
 	apply_command();
-	clear_selection();
 }
 
+
 void
+MidiRegionView::change_velocity(uint8_t velocity, bool relative)
+{
+	start_delta_command();
+	for (Selection::iterator i = _selection.begin(); i != _selection.end();) {
+		Selection::iterator next = i;
+		++next;
+
+		CanvasMidiEvent *event = *i;
+		const boost::shared_ptr<Note> copy(new Note(*(event->note().get())));
+
+		if(relative) {
+			uint8_t new_velocity = copy->velocity() + velocity;
+			clamp_0_to_127(new_velocity);
+				
+			copy->set_velocity(new_velocity);
+		} else { // absolute
+			copy->set_velocity(velocity);			
+		}
+		
+		command_remove_note(event);
+		command_add_note(copy);
+		
+		_marked_for_selection.insert(copy.get());
+		i = next;
+	}
+	
+	// dont keep notes selected if tweaking a single note
+	if(_marked_for_selection.size() == 1) {
+		_marked_for_selection.clear();
+	}
+	
+	apply_command();
+}
+
+
+void
 MidiRegionView::note_entered(ArdourCanvas::CanvasMidiEvent* ev)
 {
 	if (ev->note() && _mouse_state == EraseTouchDragging) {

hansfbaier

2008-03-31 00:52

reporter   ~0004819

please use the latest diff: It has the feature of note velocities shown
when hovered on or selected.

timbyr

2008-04-09 01:25

developer   ~0004846

have you committed this patch now that you have commit access?

timbyr

2008-04-14 12:40

developer   ~0004863

This patch was committed in rev branches/3.0@3211

Issue History

Date Modified Username Field Change
2008-03-28 05:21 hansfbaier New Issue
2008-03-28 05:21 hansfbaier File Added: implemented_editing_velocities_and_improved_selection_model_and_bugfixes_midi_region_view.diff
2008-03-31 00:51 hansfbaier File Added: implemented_editing_velocities_and_bugfixes_midi_region_view.diff
2008-03-31 00:52 hansfbaier Note Added: 0004819
2008-04-09 01:25 timbyr Note Added: 0004846
2008-04-14 12:40 timbyr Status new => closed
2008-04-14 12:40 timbyr Note Added: 0004863
2008-04-14 12:40 timbyr Resolution open => fixed