X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmidi_region_view.cc;h=1ca948f86075590a28475c283449e9753ee7ab35;hb=71a4796dc3dbf8a7fe1df5c5d7acea388b40eae0;hp=5eb6e55c9fde7e75e4505387177fd07e9191d66a;hpb=db55b149eb6b65bc3efa723ebe266f1035bb702f;p=ardour.git diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 5eb6e55c9f..1ca948f860 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -40,6 +40,7 @@ #include "ardour/session.h" #include "evoral/Parameter.hpp" +#include "evoral/MIDIParameters.hpp" #include "evoral/Control.hpp" #include "evoral/midi_util.h" @@ -59,6 +60,7 @@ #include "midi_time_axis.h" #include "midi_util.h" #include "public_editor.h" +#include "rgb_macros.h" #include "selection.h" #include "simpleline.h" #include "streamview.h" @@ -86,6 +88,9 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView & , _diff_command(0) , _ghost_note(0) , _drag_rect (0) + , _step_edit_cursor (0) + , _step_edit_cursor_width (1.0) + , _step_edit_cursor_position (0.0) , _mouse_state(None) , _pressed_button(0) , _sort_needed (true) @@ -558,7 +563,7 @@ MidiRegionView::key_press (GdkEventKey* ev) bool shorter = Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier); bool fine = Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier); - change_note_lengths (fine, shorter, start, end); + change_note_lengths (fine, shorter, 0.0, start, end); return true; @@ -612,13 +617,7 @@ MidiRegionView::key_press (GdkEventKey* ev) } else if (ev->keyval == GDK_Control_L) { return true; - - } else if (ev->keyval == GDK_r) { - /* yes, this steals r */ - if (midi_view()->midi_track()->step_editing()) { - midi_view()->step_edit_rest (); - return true; - } + } return false; @@ -674,9 +673,28 @@ MidiRegionView::create_note_at(double x, double y, double length, bool sh) length = frames_to_beats (beats_to_frames (length) - 1); } - const boost::shared_ptr new_note(new NoteType(0, - frames_to_beats(start_frames + _region->start()), length, - (uint8_t)note, 0x40)); + uint16_t chn_mask = mtv->channel_selector().get_selected_channels(); + int chn_cnt = 0; + uint8_t channel = 0; + + /* pick the highest selected channel, unless all channels are selected, + which is interpreted to mean channel 1 (zero) + */ + + for (uint16_t i = 0; i < 16; ++i) { + if (chn_mask & (1< new_note (new NoteType (channel, + frames_to_beats(start_frames + _region->start()), length, + (uint8_t)note, 0x40)); if (_model->contains (new_note)) { return; @@ -797,7 +815,6 @@ MidiRegionView::apply_diff () _model->apply_command(*trackview.session(), _diff_command); _diff_command = 0; midi_view()->midi_track()->playlist_modified(); - if (add_or_remove) { _marked_for_selection.clear(); @@ -950,6 +967,9 @@ MidiRegionView::redisplay_model() } } + _pgm_changes.clear(); + _sys_exes.clear(); + display_sysexes(); display_program_changes(); @@ -967,15 +987,28 @@ MidiRegionView::redisplay_model() void MidiRegionView::display_program_changes() { - boost::shared_ptr control = _model->control(MidiPgmChangeAutomation); + MidiTimeAxisView* const mtv = dynamic_cast(&trackview); + uint16_t chn_mask = mtv->channel_selector().get_selected_channels(); + + for (uint8_t i = 0; i < 16; ++i) { + if (chn_mask & (1< control = + _model->control(Evoral::MIDI::ProgramChange (MidiPgmChangeAutomation, channel)); + if (!control) { return; } Glib::Mutex::Lock lock (control->list()->lock()); - uint8_t channel = control->parameter().channel(); - for (AutomationList::const_iterator event = control->list()->begin(); event != control->list()->end(); ++event) { double event_time = (*event)->when; @@ -986,7 +1019,7 @@ MidiRegionView::display_program_changes() boost::shared_ptr msb_control = _model->control(bank_select_msb); uint8_t msb = 0; if (msb_control != 0) { - msb = uint8_t(floor(msb_control->get_float(true, event_time) + 0.5)); + msb = uint8_t(floor(msb_control->get_double(true, event_time) + 0.5)); } // Get current value of bank select LSB at time of the program change @@ -994,7 +1027,7 @@ MidiRegionView::display_program_changes() boost::shared_ptr lsb_control = _model->control(bank_select_lsb); uint8_t lsb = 0; if (lsb_control != 0) { - lsb = uint8_t(floor(lsb_control->get_float(true, event_time) + 0.5)); + lsb = uint8_t(floor(lsb_control->get_double(true, event_time) + 0.5)); } MIDI::Name::PatchPrimaryKey patch_key(msb, lsb, program_number); @@ -1009,7 +1042,8 @@ MidiRegionView::display_program_changes() add_pgm_change(program_change, patch->name()); } else { char buf[4]; - snprintf(buf, 4, "%d", int(program_number)); + // program_number is zero-based: convert to one-based + snprintf(buf, 4, "%d", int(program_number+1)); add_pgm_change(program_change, buf); } } @@ -1057,6 +1091,8 @@ MidiRegionView::~MidiRegionView () { in_destructor = true; + trackview.editor().hide_verbose_canvas_cursor (); + note_delete_connection.disconnect (); delete _list_editor; @@ -1069,8 +1105,10 @@ MidiRegionView::~MidiRegionView () _selection.clear(); clear_events(); + delete _note_group; delete _diff_command; + delete _step_edit_cursor; } void @@ -1095,6 +1133,9 @@ MidiRegionView::reset_width_dependent_items (double pixel_width) if (_enable_display) { redisplay_model(); } + + move_step_edit_cursor (_step_edit_cursor_position); + set_step_edit_cursor_width (_step_edit_cursor_width); } void @@ -1112,6 +1153,14 @@ MidiRegionView::set_height (double height) if (name_pixbuf) { name_pixbuf->raise_to_top(); } + + for (PgmChanges::iterator x = _pgm_changes.begin(); x != _pgm_changes.end(); ++x) { + (*x)->set_height (midi_stream_view()->contents_height()); + } + + if (_step_edit_cursor) { + _step_edit_cursor->property_y2() = midi_stream_view()->contents_height(); + } } @@ -1311,7 +1360,9 @@ MidiRegionView::update_note (CanvasNote* ev) boost::shared_ptr note = ev->note(); const nframes64_t note_start_frames = beats_to_frames(note->time()); - const nframes64_t note_end_frames = beats_to_frames(note->end_time()); + + /* trim note display to not overlap the end of its region */ + const nframes64_t note_end_frames = min (beats_to_frames (note->end_time()), _region->start() + _region->length()); const double x = trackview.editor().frame_to_pixel(note_start_frames - _region->start()); const double y1 = midi_stream_view()->note_to_y(note->note()); @@ -1409,7 +1460,7 @@ MidiRegionView::add_note(const boost::shared_ptr note, bool visible) if (event) { if (_marked_for_selection.find(note) != _marked_for_selection.end()) { note_selected(event, true); - } + } if (_marked_for_velocity.find(note) != _marked_for_velocity.end()) { event->show_velocity(); @@ -1426,25 +1477,34 @@ MidiRegionView::add_note(const boost::shared_ptr note, bool visible) } void -MidiRegionView::add_note (uint8_t channel, uint8_t number, uint8_t velocity, - Evoral::MusicalTime pos, Evoral::MusicalTime len) +MidiRegionView::step_add_note (uint8_t channel, uint8_t number, uint8_t velocity, + Evoral::MusicalTime pos, Evoral::MusicalTime len) { boost::shared_ptr new_note (new NoteType (channel, pos, len, number, velocity)); - start_diff_command (_("step add")); - diff_add_note (new_note, true, false); - apply_diff(); - /* potentially extend region to hold new note */ nframes64_t end_frame = _region->position() + beats_to_frames (new_note->end_time()); nframes64_t region_end = _region->position() + _region->length() - 1; if (end_frame > region_end) { - _region->set_length (end_frame, this); - } else { - redisplay_model (); + _region->set_length (end_frame - _region->position(), this); } + + _marked_for_selection.clear (); + clear_selection (); + + start_diff_command (_("step add")); + diff_add_note (new_note, true, false); + apply_diff(); + + // last_step_edit_note = new_note; +} + +void +MidiRegionView::step_sustain (Evoral::MusicalTime beats) +{ + change_note_lengths (false, false, beats, false, true); } void @@ -1479,29 +1539,25 @@ MidiRegionView::add_pgm_change(PCEvent& program, const string& displaytext) void MidiRegionView::get_patch_key_at(double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) { - cerr << "getting patch key at " << time << " for channel " << channel << endl; Evoral::Parameter bank_select_msb(MidiCCAutomation, channel, MIDI_CTL_MSB_BANK); boost::shared_ptr msb_control = _model->control(bank_select_msb); - float msb = -1.0; + double msb = 0.0; if (msb_control != 0) { - msb = int(msb_control->get_float(true, time)); - cerr << "got msb " << msb; + msb = int(msb_control->get_double(true, time)); } Evoral::Parameter bank_select_lsb(MidiCCAutomation, channel, MIDI_CTL_LSB_BANK); boost::shared_ptr lsb_control = _model->control(bank_select_lsb); - float lsb = -1.0; + double lsb = 0.0; if (lsb_control != 0) { - lsb = lsb_control->get_float(true, time); - cerr << " got lsb " << lsb; + lsb = lsb_control->get_double(true, time); } Evoral::Parameter program_change(MidiPgmChangeAutomation, channel, 0); boost::shared_ptr program_control = _model->control(program_change); - float program_number = -1.0; + double program_number = -1.0; if (program_control != 0) { - program_number = program_control->get_float(true, time); - cerr << " got program " << program_number << endl; + program_number = program_control->get_double(true, time); } key.msb = (int) floor(msb + 0.5); @@ -1518,23 +1574,24 @@ MidiRegionView::alter_program_change(PCEvent& old_program, const MIDI::Name::Pat Evoral::Parameter bank_select_msb(MidiCCAutomation, old_program.channel, MIDI_CTL_MSB_BANK); boost::shared_ptr msb_control = _model->control(bank_select_msb); if (msb_control != 0) { - msb_control->set_float(float(new_patch.msb), true, old_program.time); + msb_control->set_double(double(new_patch.msb), true, old_program.time); } // TODO: Get the real event here and alter them at the original times Evoral::Parameter bank_select_lsb(MidiCCAutomation, old_program.channel, MIDI_CTL_LSB_BANK); boost::shared_ptr lsb_control = _model->control(bank_select_lsb); if (lsb_control != 0) { - lsb_control->set_float(float(new_patch.lsb), true, old_program.time); + lsb_control->set_double(double(new_patch.lsb), true, old_program.time); } Evoral::Parameter program_change(MidiPgmChangeAutomation, old_program.channel, 0); boost::shared_ptr program_control = _model->control(program_change); assert(program_control != 0); - program_control->set_float(float(new_patch.program_number), true, old_program.time); + program_control->set_double(float(new_patch.program_number), true, old_program.time); - redisplay_model(); + _pgm_changes.clear (); + display_program_changes (); // XXX would be nice to limit to just old_program.channel } void @@ -1547,39 +1604,27 @@ MidiRegionView::program_selected(CanvasProgramChange& program, const MIDI::Name: void MidiRegionView::previous_program(CanvasProgramChange& program) { - MIDI::Name::PatchPrimaryKey key; - get_patch_key_at(program.event_time(), program.channel(), key); + if (program.program() < 127) { + MIDI::Name::PatchPrimaryKey key; + get_patch_key_at(program.event_time(), program.channel(), key); + PCEvent program_change_event(program.event_time(), program.program(), program.channel()); - boost::shared_ptr patch = - MIDI::Name::MidiPatchManager::instance().previous_patch( - _model_name, - _custom_device_mode, - program.channel(), - key); - - PCEvent program_change_event(program.event_time(), program.program(), program.channel()); - if (patch) { - alter_program_change(program_change_event, patch->patch_primary_key()); - } + key.program_number++; + alter_program_change(program_change_event, key); + } } void MidiRegionView::next_program(CanvasProgramChange& program) { - MIDI::Name::PatchPrimaryKey key; - get_patch_key_at(program.event_time(), program.channel(), key); - - boost::shared_ptr patch = - MIDI::Name::MidiPatchManager::instance().next_patch( - _model_name, - _custom_device_mode, - program.channel(), - key); + if (program.program() > 0) { + MIDI::Name::PatchPrimaryKey key; + get_patch_key_at(program.event_time(), program.channel(), key); + PCEvent program_change_event(program.event_time(), program.program(), program.channel()); - PCEvent program_change_event(program.event_time(), program.program(), program.channel()); - if (patch) { - alter_program_change(program_change_event, patch->patch_primary_key()); - } + key.program_number--; + alter_program_change(program_change_event, key); + } } void @@ -1911,7 +1956,7 @@ MidiRegionView::move_selection(double dx, double dy) } void -MidiRegionView::note_dropped(CanvasNoteEvent *, double dt, int8_t dnote) +MidiRegionView::note_dropped(CanvasNoteEvent *, frameoffset_t dt, int8_t dnote) { assert (!_selection.empty()); @@ -1946,15 +1991,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent *, double dt, int8_t dnote) for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) { - nframes64_t start_frames = beats_to_frames((*i)->note()->time()); - - if (dt >= 0) { - start_frames += snap_frame_to_frame(trackview.editor().pixel_to_frame(dt)); - } else { - start_frames -= snap_frame_to_frame(trackview.editor().pixel_to_frame(-dt)); - } - - Evoral::MusicalTime new_time = frames_to_beats(start_frames); + Evoral::MusicalTime new_time = frames_to_beats (beats_to_frames ((*i)->note()->time()) + dt); if (new_time < 0) { continue; @@ -2215,6 +2252,12 @@ MidiRegionView::commit_resizing (ArdourCanvas::CanvasNote* primary, bool at_fron apply_diff(); } +void +MidiRegionView::change_note_channel (CanvasNoteEvent* event, int8_t channel) +{ + diff_add_change (event, MidiModel::DiffCommand::Channel, (uint8_t) channel); +} + void MidiRegionView::change_note_velocity(CanvasNoteEvent* event, int8_t velocity, bool relative) { @@ -2341,6 +2384,12 @@ MidiRegionView::change_note_time (CanvasNoteEvent* event, Evoral::MusicalTime de diff_add_change (event, MidiModel::DiffCommand::StartTime, new_time); } +void +MidiRegionView::change_note_length (CanvasNoteEvent* event, Evoral::MusicalTime t) +{ + diff_add_change (event, MidiModel::DiffCommand::Length, t); +} + void MidiRegionView::change_velocities (bool up, bool fine, bool allow_smush) { @@ -2377,14 +2426,14 @@ MidiRegionView::change_velocities (bool up, bool fine, bool allow_smush) i = next; } + apply_diff(); + if (!_selection.empty()) { char buf[24]; snprintf (buf, sizeof (buf), "Vel %d", (int) (*_selection.begin())->note()->velocity()); trackview.editor().show_verbose_canvas_cursor_with (buf); } - - apply_diff(); } @@ -2434,22 +2483,22 @@ MidiRegionView::transpose (bool up, bool fine, bool allow_smush) } void -MidiRegionView::change_note_lengths (bool fine, bool shorter, bool start, bool end) +MidiRegionView::change_note_lengths (bool fine, bool shorter, Evoral::MusicalTime delta, bool start, bool end) { - Evoral::MusicalTime delta; - - if (fine) { - delta = 1.0/128.0; - } else { - /* grab the current grid distance */ - bool success; - delta = trackview.editor().get_grid_type_as_beats (success, _region->position()); - if (!success) { - /* XXX cannot get grid type as beats ... should always be possible ... FIX ME */ - cerr << "Grid type not available as beats - TO BE FIXED\n"; - return; - } - } + if (delta == 0.0) { + if (fine) { + delta = 1.0/128.0; + } else { + /* grab the current grid distance */ + bool success; + delta = trackview.editor().get_grid_type_as_beats (success, _region->position()); + if (!success) { + /* XXX cannot get grid type as beats ... should always be possible ... FIX ME */ + cerr << "Grid type not available as beats - TO BE FIXED\n"; + return; + } + } + } if (shorter) { delta = -delta; @@ -2940,3 +2989,60 @@ MidiRegionView::color_handler () /* XXX probably more to do here */ } + +void +MidiRegionView::enable_display (bool yn) +{ + RegionView::enable_display (yn); + if (yn) { + redisplay_model (); + } +} + +void +MidiRegionView::show_step_edit_cursor (Evoral::MusicalTime pos) +{ + if (_step_edit_cursor == 0) { + ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group(); + + _step_edit_cursor = new ArdourCanvas::SimpleRect (*group); + _step_edit_cursor->property_y1() = 0; + _step_edit_cursor->property_y2() = midi_stream_view()->contents_height(); + _step_edit_cursor->property_fill_color_rgba() = RGBA_TO_UINT (45,0,0,90); + _step_edit_cursor->property_outline_color_rgba() = RGBA_TO_UINT (85,0,0,90); + } + + move_step_edit_cursor (pos); + _step_edit_cursor->show (); +} + +void +MidiRegionView::move_step_edit_cursor (Evoral::MusicalTime pos) +{ + _step_edit_cursor_position = pos; + + if (_step_edit_cursor) { + double pixel = trackview.editor().frame_to_pixel (beats_to_frames (pos)); + _step_edit_cursor->property_x1() = pixel; + set_step_edit_cursor_width (_step_edit_cursor_width); + } +} + +void +MidiRegionView::hide_step_edit_cursor () +{ + if (_step_edit_cursor) { + _step_edit_cursor->hide (); + } +} + +void +MidiRegionView::set_step_edit_cursor_width (Evoral::MusicalTime beats) +{ + _step_edit_cursor_width = beats; + + if (_step_edit_cursor) { + _step_edit_cursor->property_x2() = _step_edit_cursor->property_x1() + trackview.editor().frame_to_pixel (beats_to_frames (beats)); + } +} +