move assignments out of assert() in editor_drag (thanks lincoln); change mouse mode buttons when in internal/MIDI mode; arrow key control of note velocity, value and position - hey look ma, MIDI editing!

git-svn-id: svn://localhost/ardour2/branches/3.0@5539 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-08-17 15:58:47 +00:00
parent 902a087f15
commit 3162ffb4f4
7 changed files with 216 additions and 26 deletions

View File

@ -224,24 +224,8 @@ CanvasNoteEvent::on_event(GdkEvent* ev)
static double last_x, last_y;
double event_x, event_y, dx, dy;
bool select_mod;
uint8_t d_velocity = 10;
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.change_velocity(this, d_velocity, true);
return true;
} else if (ev->scroll.direction == GDK_SCROLL_DOWN) {
_region.change_velocity(this, -d_velocity, true);
return true;
} else {
return false;
}
case GDK_ENTER_NOTIFY:
_region.note_entered(this);
//_item->grab_focus();

View File

@ -891,10 +891,14 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
/* get the playlist where this drag started. we can't use rv->region()->playlist()
because we may have copied the region and it has not been attached to a playlist.
*/
source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
ds = source_tv->get_diskstream();
from_playlist = ds->playlist();
assert ((source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view())));
assert ((ds = source_tv->get_diskstream()));
assert ((from_playlist = ds->playlist()));
assert (source_tv);
assert (ds);
assert (from_playlist);
/* moved to a different audio track, without copying */

View File

@ -2558,5 +2558,14 @@ void
Editor::set_internal_edit (bool yn)
{
_internal_editing = yn;
if (yn) {
mouse_select_button.set_image (*(manage (new Image (::get_icon("midi_tool_select")))));
mouse_move_button.set_image (*(manage (new Image (::get_icon("midi_tool_pencil")))));
} else {
mouse_select_button.set_image (*(manage (new Image (::get_xpm("tool_range.xpm")))));
mouse_move_button.set_image (*(manage (new Image (::get_icon("tool_object")))));
}
set_canvas_cursor ();
}

View File

@ -210,10 +210,27 @@ MidiRegionView::canvas_event(GdkEvent* ev)
static double last_x, last_y;
double event_x, event_y;
nframes64_t event_frame = 0;
uint8_t d_velocity = 10;
static ArdourCanvas::SimpleRect* drag_rect = NULL;
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) {
change_velocities (d_velocity, true);
return true;
} else if (ev->scroll.direction == GDK_SCROLL_DOWN) {
change_velocities(-d_velocity, true);
return true;
} else {
return false;
}
break;
case GDK_KEY_PRESS:
if (ev->key.keyval == GDK_Shift_L || ev->key.keyval == GDK_Control_L) {
_mouse_state = SelectTouchDragging;
@ -232,6 +249,36 @@ MidiRegionView::canvas_event(GdkEvent* ev)
} else if (ev->key.keyval == GDK_Shift_L || ev->key.keyval == GDK_Control_L) {
_mouse_state = None;
return true;
} else if (ev->key.keyval == GDK_Tab) {
if (Keyboard::modifier_state_equals (ev->key.state, Keyboard::PrimaryModifier)) {
goto_previous_note ();
} else {
goto_next_note ();
}
return true;
} else if (ev->key.keyval == GDK_Up) {
if (Keyboard::modifier_state_equals (ev->key.state, Keyboard::PrimaryModifier)) {
change_velocities (1, true);
} else {
transpose (true, false);
}
} else if (ev->key.keyval == GDK_Down) {
if (Keyboard::modifier_state_equals (ev->key.state, Keyboard::PrimaryModifier)) {
change_velocities (-1, true);
} else {
transpose (false, false);
}
} else if (ev->key.keyval == GDK_Left) {
nudge_notes (-1.0);
} else if (ev->key.keyval == GDK_Right) {
nudge_notes (1.0);
}
return false;
@ -468,7 +515,6 @@ MidiRegionView::clear_events()
void
MidiRegionView::display_model(boost::shared_ptr<MidiModel> model)
{
cerr << "MRV: display mode, enable = " << _enable_display << endl;
_model = model;
content_connection.disconnect ();
content_connection = _model->ContentsChanged.connect(sigc::mem_fun(this, &MidiRegionView::redisplay_model));
@ -542,7 +588,6 @@ MidiRegionView::abort_command()
void
MidiRegionView::redisplay_model()
{
cerr << "MRV: display mode, active notes = " << _active_notes << endl;
// Don't redisplay the model if we're currently recording and displaying that
if (_active_notes) {
return;
@ -1569,6 +1614,46 @@ MidiRegionView::change_note_velocity(CanvasNoteEvent* event, int8_t velocity, bo
command_add_note(copy, event->selected(), true);
}
void
MidiRegionView::change_note_note (CanvasNoteEvent* event, int8_t note, bool relative)
{
const boost::shared_ptr<NoteType> copy(new NoteType(*(event->note().get())));
if (relative) {
uint8_t new_note = copy->note() + note;
clamp_to_0_127(new_note);
copy->set_note(new_note);
} else {
copy->set_note(note);
}
command_remove_note(event);
command_add_note(copy, event->selected(), false);
}
void
MidiRegionView::change_note_time (CanvasNoteEvent* event, MidiModel::TimeType delta, bool relative)
{
const boost::shared_ptr<NoteType> copy(new NoteType(*(event->note().get())));
if (relative) {
if (delta < 0.0) {
if (copy->time() < -delta) {
copy->set_time (0);
} else {
copy->set_time (copy->time() + delta);
}
} else {
copy->set_time (copy->time() + delta);
}
} else {
copy->set_time (delta);
}
command_remove_note(event);
command_add_note(copy, event->selected(), false);
}
void
MidiRegionView::change_velocity(CanvasNoteEvent* ev, int8_t velocity, bool relative)
{
@ -1588,6 +1673,66 @@ MidiRegionView::change_velocity(CanvasNoteEvent* ev, int8_t velocity, bool relat
apply_command();
}
void
MidiRegionView::change_velocities (int8_t velocity, bool relative)
{
start_delta_command(_("change velocities"));
for (Selection::iterator i = _selection.begin(); i != _selection.end();) {
Selection::iterator next = i;
++next;
change_note_velocity (*i, velocity, relative);
i = next;
}
apply_command();
}
void
MidiRegionView::transpose (bool up, bool fine)
{
int8_t delta;
if (fine) {
delta = 1;
} else {
delta = 12;
}
if (!up) {
delta = -delta;
}
start_delta_command (_("transpose"));
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
Selection::iterator next = i;
++next;
change_note_note (*i, delta, true);
i = next;
}
apply_command ();
}
void
MidiRegionView::nudge_notes (MidiModel::TimeType delta)
{
start_delta_command (_("nudge"));
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
Selection::iterator next = i;
++next;
change_note_time (*i, delta, true);
i = next;
}
apply_command ();
}
void
MidiRegionView::change_channel(uint8_t channel)
{
@ -1752,6 +1897,7 @@ MidiRegionView::paste (nframes64_t pos, float times, const MidiCutBuffer& mcb)
copied_note->set_time (paste_pos_beats + copied_note->time() - beat_delta);
/* make all newly added notes selected */
cerr << "\tadd @ " << copied_note->time() << endl;
command_add_note (copied_note, true);
end_point = copied_note->end_time();
@ -1762,14 +1908,51 @@ MidiRegionView::paste (nframes64_t pos, float times, const MidiCutBuffer& mcb)
/* if we pasted past the current end of the region, extend the region */
nframes64_t end_frame = beats_to_frames (end_point);
nframes64_t end_frame = _region->position() + beats_to_frames (end_point);
nframes64_t region_end = _region->position() + _region->length() - 1;
cerr << "\tEnd frame = " << end_frame << " from " << end_point << " region end = " << region_end << endl;
if (end_frame > region_end) {
trackview.session().begin_reversible_command (_("paste"));
XMLNode& before (_region->get_state());
_region->set_length (end_frame, this);
cerr << "\textended to " << end_frame << endl;
trackview.session().add_command (new MementoCommand<Region>(*_region, &before, &_region->get_state()));
}
apply_command ();
}
void
MidiRegionView::goto_next_note ()
{
nframes64_t pos = trackview.session().transport_frame();
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
nframes64_t npos = _region->position() + beats_to_frames ((*i)->note()->time());
if (npos >= pos && !(*i)->selected()) {
unique_select (*i);
trackview.session().request_locate (npos);
return;
}
}
}
void
MidiRegionView::goto_previous_note ()
{
nframes64_t pos = trackview.session().transport_frame();
for (Events::reverse_iterator i = _events.rbegin(); i != _events.rend(); ++i) {
nframes64_t npos = _region->position() + beats_to_frames ((*i)->note()->time());
if (npos <= pos && !(*i)->selected()) {
unique_select (*i);
trackview.session().request_locate (npos);
return;
}
}
}

View File

@ -260,7 +260,13 @@ class MidiRegionView : public RegionView
/** Return the current selection as a MidiModel or null if there is no selection */
ARDOUR::MidiModel* selection_as_model () const;
void goto_previous_note ();
void goto_next_note ();
void change_velocities (int8_t velocity, bool relative);
void transpose (bool up, bool fine);
void nudge_notes (ARDOUR::MidiModel::TimeType delta);
protected:
/** Allows derived types to specify their visibility requirements
* to the TimeAxisViewItem parent class.
@ -300,6 +306,8 @@ class MidiRegionView : public RegionView
void midi_patch_settings_changed(std::string model, std::string custom_device_mode);
void change_note_velocity(ArdourCanvas::CanvasNoteEvent* ev, int8_t vel, bool relative=false);
void change_note_note(ArdourCanvas::CanvasNoteEvent* ev, int8_t note, bool relative=false);
void change_note_time(ArdourCanvas::CanvasNoteEvent* ev, ARDOUR::MidiModel::TimeType, bool relative=false);
void clear_selection_except(ArdourCanvas::CanvasNoteEvent* ev);
void clear_selection() { clear_selection_except(NULL); }

View File

@ -2151,10 +2151,12 @@ Session::begin_reversible_command(const string& name)
{
UndoTransaction* trans = new UndoTransaction();
trans->set_name(name);
if (!_current_trans.empty()) {
_current_trans.top()->add_command(trans);
_current_trans.top()->add_command (trans);
} else {
_current_trans.push(trans);
}
_current_trans.push(trans);
}
void

View File

@ -39,7 +39,7 @@ Note<Time>::Note(uint8_t chan, Time t, Time l, uint8_t n, uint8_t v)
_off_event.buffer()[2] = 0x40;
assert(time() == t);
assert(length() - l <= std::numeric_limits<Time>::epsilon());
assert(length() - l <= 1.0/1920.0); /* acceptable tolerance is 1/ppqn. Nice if there was no magic number here */
assert(note() == n);
assert(velocity() == v);
assert(_on_event.channel() == _off_event.channel());