#include "ardour/session.h"
#include "evoral/Parameter.hpp"
+#include "evoral/MIDIParameters.hpp"
#include "evoral/Control.hpp"
#include "evoral/midi_util.h"
#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"
, _custom_device_mode(string())
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*parent))
- , _delta_command(0)
, _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)
, _custom_device_mode(string())
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*parent))
- , _delta_command(0)
, _diff_command(0)
, _ghost_note(0)
, _drag_rect (0)
, _custom_device_mode(string())
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*get_canvas_group()))
- , _delta_command(0)
, _diff_command(0)
, _ghost_note(0)
, _drag_rect (0)
, _custom_device_mode(string())
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*get_canvas_group()))
- , _delta_command(0)
, _diff_command(0)
, _ghost_note(0)
, _drag_rect (0)
_mouse_state = Pressed;
return true;
}
+
_pressed_button = ev->button;
return true;
if (!success) {
beats = 1;
}
-
- create_note_at (event_x, event_y, beats);
+ create_note_at (event_x, event_y, beats, true);
break;
}
default:
const double length = trackview.editor().pixel_to_frame
(_drag_rect->property_x2() - _drag_rect->property_x1());
- create_note_at (x, _drag_rect->property_y1(), frames_to_beats(length));
+ create_note_at (x, _drag_rect->property_y1(), frames_to_beats(length), false);
}
delete _drag_rect;
trackview.editor().hide_verbose_canvas_cursor ();
- bool fine = Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier);
+ bool fine = !Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier);
if (ev->direction == GDK_SCROLL_UP) {
change_velocities (true, fine, false);
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;
} else if (ev->keyval == GDK_Control_L) {
return true;
-
- } else if (ev->keyval == GDK_r) {
- /* if we're not step editing, this really doesn't matter */
- midi_view()->step_edit_rest ();
- return true;
+
}
return false;
/** Add a note to the model, and the view, at a canvas (click) coordinate.
* \param x horizontal position in pixels
* \param y vertical position in pixels
- * \param length duration of the note in beats */
+ * \param length duration of the note in beats, which will be snapped to the grid
+ * \param sh true to make the note 1 frame shorter than the snapped version of \a length.
+ */
void
-MidiRegionView::create_note_at(double x, double y, double length)
+MidiRegionView::create_note_at(double x, double y, double length, bool sh)
{
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
MidiStreamView* const view = mtv->midi_view();
assert (length != 0);
- const boost::shared_ptr<NoteType> new_note(new NoteType(0,
- frames_to_beats(start_frames + _region->start()), length,
- (uint8_t)note, 0x40));
+ if (sh) {
+ length = frames_to_beats (beats_to_frames (length) - 1);
+ }
+
+ 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<<i)) {
+ channel = i;
+ chn_cnt++;
+ }
+ }
+
+ if (chn_cnt == 16) {
+ channel = 0;
+ }
+
+ const boost::shared_ptr<NoteType> new_note (new NoteType (channel,
+ frames_to_beats(start_frames + _region->start()), length,
+ (uint8_t)note, 0x40));
if (_model->contains (new_note)) {
return;
view->update_note_range(new_note->note());
- MidiModel::DeltaCommand* cmd = _model->new_delta_command("add note");
+ MidiModel::DiffCommand* cmd = _model->new_diff_command("add note");
cmd->add(new_note);
_model->apply_command(*trackview.session(), cmd);
}
}
-
-void
-MidiRegionView::start_delta_command(string name)
-{
- if (!_delta_command) {
- _delta_command = _model->new_delta_command(name);
- }
-}
-
void
MidiRegionView::start_diff_command(string name)
{
}
void
-MidiRegionView::delta_add_note(const boost::shared_ptr<NoteType> note, bool selected, bool show_velocity)
+MidiRegionView::diff_add_note(const boost::shared_ptr<NoteType> note, bool selected, bool show_velocity)
{
- if (_delta_command) {
- _delta_command->add(note);
+ if (_diff_command) {
+ _diff_command->add(note);
}
if (selected) {
_marked_for_selection.insert(note);
}
void
-MidiRegionView::delta_remove_note(ArdourCanvas::CanvasNoteEvent* ev)
+MidiRegionView::diff_remove_note(ArdourCanvas::CanvasNoteEvent* ev)
{
- if (_delta_command && ev->note()) {
- _delta_command->remove(ev->note());
+ if (_diff_command && ev->note()) {
+ _diff_command->remove(ev->note());
}
}
}
}
-void
-MidiRegionView::apply_delta()
-{
- if (!_delta_command) {
- return;
- }
-
- // Mark all selected notes for selection when model reloads
- for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
- _marked_for_selection.insert((*i)->note());
- }
-
- _model->apply_command(*trackview.session(), _delta_command);
- _delta_command = 0;
- midi_view()->midi_track()->playlist_modified();
-
- _marked_for_selection.clear();
- _marked_for_velocity.clear();
-}
-
void
MidiRegionView::apply_diff ()
{
+ bool add_or_remove;
+
if (!_diff_command) {
return;
}
+ if ((add_or_remove = _diff_command->adds_or_removes())) {
+ // Mark all selected notes for selection when model reloads
+ for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+ _marked_for_selection.insert((*i)->note());
+ }
+ }
+
_model->apply_command(*trackview.session(), _diff_command);
_diff_command = 0;
midi_view()->midi_track()->playlist_modified();
+
+ if (add_or_remove) {
+ _marked_for_selection.clear();
+ }
_marked_for_velocity.clear();
}
-void
-MidiRegionView::apply_delta_as_subcommand()
-{
- if (!_delta_command) {
- return;
- }
-
- // Mark all selected notes for selection when model reloads
- for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
- _marked_for_selection.insert((*i)->note());
- }
-
- _model->apply_command_as_subcommand(*trackview.session(), _delta_command);
- _delta_command = 0;
- midi_view()->midi_track()->playlist_modified();
-
- _marked_for_selection.clear();
- _marked_for_velocity.clear();
-}
-
void
MidiRegionView::apply_diff_as_subcommand()
{
+ bool add_or_remove;
+
if (!_diff_command) {
return;
}
- // Mark all selected notes for selection when model reloads
- for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
- _marked_for_selection.insert((*i)->note());
- }
+ if ((add_or_remove = _diff_command->adds_or_removes())) {
+ // Mark all selected notes for selection when model reloads
+ for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+ _marked_for_selection.insert((*i)->note());
+ }
+ }
_model->apply_command_as_subcommand(*trackview.session(), _diff_command);
_diff_command = 0;
midi_view()->midi_track()->playlist_modified();
- _marked_for_selection.clear();
+ if (add_or_remove) {
+ _marked_for_selection.clear();
+ }
_marked_for_velocity.clear();
}
+
void
MidiRegionView::abort_command()
{
- delete _delta_command;
- _delta_command = 0;
delete _diff_command;
_diff_command = 0;
clear_selection();
}
}
+ _pgm_changes.clear();
+ _sys_exes.clear();
+
display_sysexes();
display_program_changes();
void
MidiRegionView::display_program_changes()
{
- boost::shared_ptr<Evoral::Control> control = _model->control(MidiPgmChangeAutomation);
+ MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+ uint16_t chn_mask = mtv->channel_selector().get_selected_channels();
+
+ for (uint8_t i = 0; i < 16; ++i) {
+ if (chn_mask & (1<<i)) {
+ display_program_changes_on_channel (i);
+ }
+ }
+}
+
+void
+MidiRegionView::display_program_changes_on_channel(uint8_t channel)
+{
+ boost::shared_ptr<Evoral::Control> 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;
boost::shared_ptr<Evoral::Control> 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
boost::shared_ptr<Evoral::Control> 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);
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);
}
}
{
in_destructor = true;
+ trackview.editor().hide_verbose_canvas_cursor ();
+
note_delete_connection.disconnect ();
delete _list_editor;
_selection.clear();
clear_events();
+
delete _note_group;
- delete _delta_command;
+ delete _diff_command;
+ delete _step_edit_cursor;
}
void
if (_enable_display) {
redisplay_model();
}
+
+ move_step_edit_cursor (_step_edit_cursor_position);
+ set_step_edit_cursor_width (_step_edit_cursor_width);
}
void
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();
+ }
}
boost::shared_ptr<NoteType> 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());
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();
}
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<NoteType> new_note (new NoteType (channel, pos, len, number, velocity));
- start_delta_command (_("step add"));
- delta_add_note (new_note, true, false);
- apply_delta();
-
/* 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
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<Evoral::Control> 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<Evoral::Control> 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<Evoral::Control> 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);
Evoral::Parameter bank_select_msb(MidiCCAutomation, old_program.channel, MIDI_CTL_MSB_BANK);
boost::shared_ptr<Evoral::Control> 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<Evoral::Control> 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<Evoral::Control> 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
void
MidiRegionView::previous_program(CanvasProgramChange& program)
{
- MIDI::Name::PatchPrimaryKey key;
- get_patch_key_at(program.event_time(), program.channel(), key);
-
- boost::shared_ptr<MIDI::Name::Patch> patch =
- MIDI::Name::MidiPatchManager::instance().previous_patch(
- _model_name,
- _custom_device_mode,
- 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());
- 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<MIDI::Name::Patch> 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
return;
}
- start_delta_command (_("delete selection"));
+ start_diff_command (_("delete selection"));
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
if ((*i)->selected()) {
- _delta_command->remove((*i)->note());
+ _diff_command->remove((*i)->note());
}
}
_selection.clear();
- apply_delta ();
+ apply_diff ();
}
void
MidiRegionView::delete_note (boost::shared_ptr<NoteType> n)
{
- start_delta_command (_("delete note"));
- _delta_command->remove (n);
- apply_delta ();
+ start_diff_command (_("delete note"));
+ _diff_command->remove (n);
+ apply_diff ();
trackview.editor().hide_verbose_canvas_cursor ();
}
{
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
if ((*i)->selected() && (*i) != ev) {
- (*i)->selected(false);
+ (*i)->set_selected(false);
(*i)->hide_velocity();
}
}
Selection::iterator tmp = i;
++tmp;
- (*i)->selected (false);
+ (*i)->set_selected (false);
_selection.erase (i);
i = tmp;
_selection.erase (i);
}
- ev->selected (false);
+ ev->set_selected (false);
ev->hide_velocity ();
if (_selection.empty()) {
}
if (_selection.insert (ev).second) {
- ev->selected (true);
+ ev->set_selected (true);
play_midi_note ((ev)->note());
}
}
void
-MidiRegionView::note_dropped(CanvasNoteEvent *, double dt, int8_t dnote)
+MidiRegionView::note_dropped(CanvasNoteEvent *, frameoffset_t dt, int8_t dnote)
{
assert (!_selection.empty());
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;
// calculate color based on note velocity
resize_rect->property_fill_color_rgba() = UINT_INTERPOLATE(
- CanvasNoteEvent::meter_style_fill_color(note->note()->velocity()),
+ CanvasNoteEvent::meter_style_fill_color(note->note()->velocity(), note->selected()),
fill_color,
0.85);
}
}
+/** Update resizing notes while user drags.
+ * @param primary `primary' note for the drag; ie the one that is used as the reference in non-relative mode.
+ * @param at_front which end of the note (true == note on, false == note off)
+ * @param delta_x change in mouse position since the start of the drag
+ * @param relative true if relative resizing is taking place, false if absolute resizing. This only makes
+ * a difference when multiple notes are being resized; in relative mode, each note's length is changed by the
+ * amount of the drag. In non-relative mode, all selected notes are set to have the same start or end point
+ * as the \a primary note.
+ */
void
-MidiRegionView::update_resizing (bool at_front, double delta_x, bool relative)
+MidiRegionView::update_resizing (ArdourCanvas::CanvasNote* primary, bool at_front, double delta_x, bool relative)
{
+ bool cursor_set = false;
+
for (std::vector<NoteResizeData *>::iterator i = _resize_data.begin(); i != _resize_data.end(); ++i) {
SimpleRect* resize_rect = (*i)->resize_rect;
CanvasNote* canvas_note = (*i)->canvas_note;
if (relative) {
current_x = canvas_note->x1() + delta_x;
} else {
- // x is in track relative, transform it to region relative
- current_x = delta_x - get_position_pixels();
+ current_x = primary->x1() + delta_x;
}
} else {
if (relative) {
current_x = canvas_note->x2() + delta_x;
} else {
- // x is in track relative, transform it to region relative
- current_x = delta_x - get_end_position_pixels ();
+ current_x = primary->x2() + delta_x;
}
}
resize_rect->property_x2() = snap_to_pixel(current_x);
resize_rect->property_x1() = canvas_note->x1();
}
+
+ if (!cursor_set) {
+ double beats;
+
+ beats = snap_pixel_to_frame (current_x);
+ beats = frames_to_beats (beats);
+
+ double len;
+
+ if (at_front) {
+ if (beats < canvas_note->note()->end_time()) {
+ len = canvas_note->note()->time() - beats;
+ len += canvas_note->note()->length();
+ } else {
+ len = 0;
+ }
+ } else {
+ if (beats >= canvas_note->note()->end_time()) {
+ len = beats - canvas_note->note()->time();
+ } else {
+ len = 0;
+ }
+ }
+
+ char buf[16];
+ snprintf (buf, sizeof (buf), "%.3g beats", len);
+ trackview.editor().show_verbose_canvas_cursor_with (buf);
+
+ cursor_set = true;
+ }
+
}
}
+
+/** Finish resizing notes when the user releases the mouse button.
+ * Parameters the same as for \a update_resizing().
+ */
void
-MidiRegionView::commit_resizing (bool at_front, double delta_x, bool relative)
+MidiRegionView::commit_resizing (ArdourCanvas::CanvasNote* primary, bool at_front, double delta_x, bool relative)
{
start_diff_command(_("resize notes"));
for (std::vector<NoteResizeData *>::iterator i = _resize_data.begin(); i != _resize_data.end(); ++i) {
CanvasNote* canvas_note = (*i)->canvas_note;
SimpleRect* resize_rect = (*i)->resize_rect;
- const double region_start = get_position_pixels();
double current_x;
if (at_front) {
if (relative) {
current_x = canvas_note->x1() + delta_x;
} else {
- // x is in track relative, transform it to region relative
- current_x = region_start + delta_x;
+ current_x = primary->x1() + delta_x;
}
} else {
if (relative) {
current_x = canvas_note->x2() + delta_x;
} else {
- // x is in track relative, transform it to region relative
- current_x = region_start + delta_x;
+ current_x = primary->x2() + delta_x;
}
}
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)
{
new_velocity = velocity;
}
- event->show_velocity ();
-
+ event->set_selected (event->selected()); // change color
+
diff_add_change (event, MidiModel::DiffCommand::Velocity, new_velocity);
}
{
bool change_start = false;
bool change_length = false;
- Evoral::MusicalTime new_start;
- Evoral::MusicalTime new_length;
+ Evoral::MusicalTime new_start = 0;
+ Evoral::MusicalTime new_length = 0;
/* NOTE: the semantics of the two delta arguments are slightly subtle:
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)
{
}
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);
+ }
}
}
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;
if (op != Copy) {
- start_delta_command();
+ start_diff_command();
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
switch (op) {
break;
case Cut:
case Clear:
- delta_remove_note (*i);
+ diff_remove_note (*i);
break;
}
}
- apply_delta();
+ apply_diff();
}
}
return;
}
- start_delta_command (_("paste"));
+ start_diff_command (_("paste"));
Evoral::MusicalTime beat_delta;
Evoral::MusicalTime paste_pos_beats;
Evoral::MusicalTime duration;
- Evoral::MusicalTime end_point;
+ Evoral::MusicalTime end_point = 0;
duration = (*mcb.notes().rbegin())->end_time() - (*mcb.notes().begin())->time();
paste_pos_beats = frames_to_beats (pos - _region->position());
for (int n = 0; n < (int) times; ++n) {
- cerr << "Pasting " << mcb.notes().size() << " for the " << n+1 << "th time\n";
-
for (Notes::const_iterator i = mcb.notes().begin(); i != mcb.notes().end(); ++i) {
boost::shared_ptr<NoteType> copied_note (new NoteType (*((*i).get())));
/* make all newly added notes selected */
- delta_add_note (copied_note, true);
+ diff_add_note (copied_note, true);
end_point = copied_note->end_time();
}
if (end_frame > region_end) {
- cerr << "region end is now " << end_frame << " to extend from " << region_end << endl;
-
trackview.session()->begin_reversible_command (_("paste"));
- _region->clear_history ();
+ _region->clear_changes ();
_region->set_length (end_frame, this);
trackview.session()->add_command (new StatefulDiffCommand (_region));
}
- cerr << "region end finally at " << _region->position() + _region->length() - 1;
- apply_delta ();
+ apply_diff ();
}
struct EventNoteTimeEarlyFirstComparator {
void
MidiRegionView::show_verbose_canvas_cursor (boost::shared_ptr<NoteType> n) const
{
- char buf[12];
- snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (n->note()).c_str(), (int) n->note ());
+ char buf[24];
+ snprintf (buf, sizeof (buf), "%s (%d)\nVel %d",
+ Evoral::midi_note_name (n->note()).c_str(),
+ (int) n->note (),
+ (int) n->velocity());
trackview.editor().show_verbose_canvas_cursor_with (buf);
}
Events e;
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+ cerr << "Selecting by position\n";
+
uint16_t chn_mask = mtv->channel_selector().get_selected_channels();
if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
for (Events::iterator i = e.begin(); i != e.end(); ++i) {
if (_selection.insert (*i).second) {
- (*i)->selected (true);
+ (*i)->set_selected (true);
}
}
editor.get_selection().add (this);
}
}
+
+void
+MidiRegionView::color_handler ()
+{
+ RegionView::color_handler ();
+
+ for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
+ (*i)->set_selected ((*i)->selected()); // will change color
+ }
+
+ /* 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));
+ }
+}
+