, _channel_selection_scoped_note (0)
, _mouse_state(None)
, _pressed_button(0)
- , _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, _no_sound_notes (false)
PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&MidiRegionView::parameter_changed, this, _1), gui_context());
+ UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MidiRegionView::parameter_changed));
+
connect_to_diskstream ();
}
, _channel_selection_scoped_note (0)
, _mouse_state(None)
, _pressed_button(0)
- , _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, _no_sound_notes (false)
if (_enable_display) {
redisplay_model();
}
+ } else if (p == "color-regions-using-track-color") {
+ set_colors ();
+ } else if (p == "use-note-color-for-velocity") {
+ color_handler ();
}
}
, _channel_selection_scoped_note (0)
, _mouse_state(None)
, _pressed_button(0)
- , _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, _no_sound_notes (false)
, _channel_selection_scoped_note (0)
, _mouse_state(None)
, _pressed_button(0)
- , _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, _no_sound_notes (false)
gui_context ());
Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&MidiRegionView::parameter_changed, this, _1), gui_context());
+ UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MidiRegionView::parameter_changed));
connect_to_diskstream ();
}
return RegionView::canvas_group_event (ev);
}
+ //For now, move the snapped cursor aside so it doesn't bother you during internal editing
+ //trackview.editor().set_snapped_cursor_position(_region->position());
+
bool r;
switch (ev->type) {
void
MidiRegionView::mouse_mode_changed ()
{
- // Adjust frame colour (become more transparent for internal tools)
- set_frame_color();
+ // Adjust sample colour (become more transparent for internal tools)
+ set_sample_color();
if (_entered) {
if (!trackview.editor().internal_editing()) {
_grabbed_keyboard = true;
}
- // Lower frame handles below notes so they don't steal events
- if (frame_handle_start) {
- frame_handle_start->lower_to_bottom();
+ // Lower sample handles below notes so they don't steal events
+ if (sample_handle_start) {
+ sample_handle_start->lower_to_bottom();
}
- if (frame_handle_end) {
- frame_handle_end->lower_to_bottom();
+ if (sample_handle_end) {
+ sample_handle_end->lower_to_bottom();
}
}
_grabbed_keyboard = false;
}
- // Raise frame handles above notes so they catch events
- if (frame_handle_start) {
- frame_handle_start->raise_to_top();
+ // Raise sample handles above notes so they catch events
+ if (sample_handle_start) {
+ sample_handle_start->raise_to_top();
}
- if (frame_handle_end) {
- frame_handle_end->raise_to_top();
+ if (sample_handle_end) {
+ sample_handle_end->raise_to_top();
}
}
}
- /* we may be dragging some non-note object (eg. patch-change, sysex)
- */
-
- return editor.drags()->motion_handler ((GdkEvent *) ev, false);
+ //let RegionView do it's thing. drags are handled in here
+ return RegionView::canvas_group_event ((GdkEvent *) ev);
}
bool
MidiRegionView::scroll (GdkEventScroll* ev)
{
+ if (trackview.editor().drags()->active()) {
+ return false;
+ }
if (_selection.empty()) {
return 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, Evoral::Beats(), start, end);
+ change_note_lengths (fine, shorter, Temporal::Beats(), start, end);
return true;
}
/** Add a note to the model, and the view, at a canvas (click) coordinate.
- * \param t time in frames relative to the position of the region
+ * \param t time in samples relative to the position of the region
* \param y vertical position in pixels
* \param length duration of the note in beats
* \param snap_t true to snap t to the grid, otherwise false.
*/
void
-MidiRegionView::create_note_at (framepos_t t, double y, Evoral::Beats length, uint32_t state, bool shift_snap)
+MidiRegionView::create_note_at (samplepos_t t, double y, Temporal::Beats length, uint32_t state, bool shift_snap)
{
if (length < 2 * DBL_EPSILON) {
return;
return;
}
- // Start of note in frames relative to region start
+ // Start of note in samples relative to region start
const int32_t divisions = trackview.editor().get_grid_music_divisions (state);
- Evoral::Beats beat_time = snap_frame_to_grid_underneath (t, divisions, shift_snap);
+ Temporal::Beats beat_time = snap_sample_to_grid_underneath (t, divisions, shift_snap);
const double note = view->y_to_note(y);
const uint8_t chan = mtv->get_channel_for_add();
start_note_diff_command(_("add note"));
- clear_editor_note_selection ();
note_diff_add_note (new_note, true, false);
apply_diff();
void
MidiRegionView::note_diff_add_change (NoteBase* ev,
MidiModel::NoteDiffCommand::Property property,
- Evoral::Beats val)
+ Temporal::Beats val)
{
if (_note_diff_command) {
_note_diff_command->change (ev->note(), property, val);
}
void
-MidiRegionView::apply_diff (bool as_subcommand)
+MidiRegionView::apply_diff (bool as_subcommand, bool was_copy)
{
- bool add_or_remove;
bool commit = false;
if (!_note_diff_command) {
return;
}
- if ((add_or_remove = _note_diff_command->adds_or_removes())) {
+ bool add_or_remove = _note_diff_command->adds_or_removes();
+
+ if (!was_copy && add_or_remove) {
// 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());
}
}
- midi_view()->midi_track()->midi_playlist()->region_edited(
- _region, _note_diff_command);
+ midi_view()->midi_track()->midi_playlist()->region_edited (_region, _note_diff_command);
if (as_subcommand) {
_model->apply_command_as_subcommand (*trackview.session(), _note_diff_command);
{
delete _note_diff_command;
_note_diff_command = 0;
+ trackview.editor().abort_reversible_command();
clear_editor_note_selection();
}
NoteBase*
MidiRegionView::find_canvas_note (boost::shared_ptr<NoteType> note)
{
+
if (_optimization_iterator != _events.end()) {
++_optimization_iterator;
}
- if (_optimization_iterator != _events.end() && (*_optimization_iterator)->note() == note) {
- return *_optimization_iterator;
+ if (_optimization_iterator != _events.end() && _optimization_iterator->first == note) {
+ return _optimization_iterator->second;
}
- for (_optimization_iterator = _events.begin(); _optimization_iterator != _events.end(); ++_optimization_iterator) {
- if ((*_optimization_iterator)->note() == note) {
- return *_optimization_iterator;
- }
+ _optimization_iterator = _events.find (note);
+ if (_optimization_iterator != _events.end()) {
+ return _optimization_iterator->second;
}
return 0;
Events::iterator it;
for (it = _events.begin(); it != _events.end(); ++it) {
- if ((*it)->note()->id() == id) {
- return *it;
+ if (it->first->id() == id) {
+ return it->second;
}
}
return boost::shared_ptr<PatchChange>();
}
+boost::shared_ptr<SysEx>
+MidiRegionView::find_canvas_sys_ex (MidiModel::SysExPtr s)
+{
+ SysExes::const_iterator f = _sys_exes.find (s);
+
+ if (f != _sys_exes.end()) {
+ return f->second;
+ }
+
+ return boost::shared_ptr<SysEx>();
+}
+
void
-MidiRegionView::get_events (Events& e, Evoral::Sequence<Evoral::Beats>::NoteOperator op, uint8_t val, int chan_mask)
+MidiRegionView::get_events (Events& e, Evoral::Sequence<Temporal::Beats>::NoteOperator op, uint8_t val, int chan_mask)
{
MidiModel::Notes notes;
_model->get_notes (notes, op, val, chan_mask);
for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) {
NoteBase* cne = find_canvas_note (*n);
if (cne) {
- e.push_back (cne);
+ e.insert (make_pair (*n, cne));
}
}
}
{
if (_active_notes) {
// Currently recording
- const framecnt_t zoom = trackview.editor().get_current_zoom();
+ const samplecnt_t zoom = trackview.editor().get_current_zoom();
if (zoom != _last_display_zoom) {
/* Update resolved canvas notes to reflect changes in zoom without
touching model. Leave active notes (with length 0) alone since
they are being extended. */
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if ((*i)->note()->length() > 0) {
- update_note(*i);
+ if (i->second->note()->length() > 0) {
+ update_note(i->second);
}
}
_last_display_zoom = zoom;
return;
}
+ for (_optimization_iterator = _events.begin(); _optimization_iterator != _events.end(); ++_optimization_iterator) {
+ _optimization_iterator->second->invalidate();
+ }
+
bool empty_when_starting = _events.empty();
- MidiModel::ReadLock lock(_model->read_lock());
- MidiModel::Notes missing_notes = _model->notes(); // copy
+ _optimization_iterator = _events.begin();
+ MidiModel::Notes missing_notes;
Note* sus = NULL;
Hit* hit = NULL;
- if (!empty_when_starting) {
- MidiModel::Notes::iterator f;
- for (Events::iterator i = _events.begin(); i != _events.end(); ) {
- boost::shared_ptr<NoteType> note = (*i)->note();
- NoteBase* cne = (*i);
+ MidiModel::ReadLock lock(_model->read_lock());
+ MidiModel::Notes& notes (_model->notes());
- /* if event item's note exists in the model, we can just update it.
- * don't mark it as missing.
- */
- if ((f = missing_notes.find (note)) != missing_notes.end()) {
- if ((*f) == note) {
- cne->validate();
- missing_notes.erase (f);
- } else {
- if (cne->selected()) {
- _marked_for_selection.insert (note);
- }
+ NoteBase* cne;
+ for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) {
- cne->invalidate();
- }
+ boost::shared_ptr<NoteType> note (*n);
+ bool visible;
+ if (note_in_region_range (note, visible)) {
+ if (!empty_when_starting && (cne = find_canvas_note (note)) != 0) {
+ cne->validate ();
+ if (visible) {
+ cne->show ();
+ } else {
+ cne->hide ();
+ }
} else {
- cne->invalidate();
+ missing_notes.insert (note);
}
+ }
+ }
+
+ if (!empty_when_starting) {
+ MidiModel::Notes::iterator f;
+ for (Events::iterator i = _events.begin(); i != _events.end(); ) {
+
+ NoteBase* cne = i->second;
+
/* remove note items that are no longer valid */
if (!cne->valid()) {
i = _events.erase (i);
} else {
- bool visible;
- bool update = false;
+ bool visible = cne->item()->visible();
- if (note_in_region_range (note, visible)) {
- if (visible) {
- update = true;
- cne->show ();
- } else {
- cne->hide ();
- }
- } else {
- cne->hide ();
- }
if ((sus = dynamic_cast<Note*>(cne))) {
- if (update) {
+ if (visible) {
update_sustained (sus);
}
- for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
- MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*i);
- if (gr && gr->trackview.y_position() != -1) {
- gr->update_note (sus, !update);
- }
- }
} else if ((hit = dynamic_cast<Hit*>(cne))) {
- if (update) {
+ if (visible) {
update_hit (hit);
}
- for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
- MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*i);
- if (gr && gr->trackview.y_position() != -1) {
- gr->update_hit (hit, !update);
- }
- }
}
++i;
}
}
}
-
for (MidiModel::Notes::iterator n = missing_notes.begin(); n != missing_notes.end(); ++n) {
boost::shared_ptr<NoteType> note (*n);
NoteBase* cne;
}
}
- _sys_exes.clear();
+ for (vector<GhostRegion*>::iterator j = ghosts.begin(); j != ghosts.end(); ++j) {
+ MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*j);
+ if (gr && !gr->trackview.hidden()) {
+ gr->redisplay_model ();
+ }
+ }
display_sysexes();
display_patch_changes ();
_marked_for_velocity.clear ();
_pending_note_selection.clear ();
- /* we may have caused _events to contain things out of order (e.g. if a note
- moved earlier or later). we don't generally need them in time order, but
- make a note that a sort is required for those cases that require it.
- */
-
- _sort_needed = true;
}
void
if ((p = find_canvas_patch_change (*i)) != 0) {
- const framecnt_t region_frames = source_beats_to_region_frames ((*i)->time());
+ const samplecnt_t region_samples = source_beats_to_region_samples ((*i)->time());
- if (region_frames < 0 || region_frames >= _region->length()) {
+ if (region_samples < 0 || region_samples >= _region->length()) {
p->hide();
} else {
- const double x = trackview.editor().sample_to_pixel (region_frames);
+ const double x = trackview.editor().sample_to_pixel (region_samples);
const string patch_name = instrument_info().get_patch_name ((*i)->bank(), (*i)->program(), channel);
p->canvas_item()->set_position (ArdourCanvas::Duple (x, 1.0));
- p->flag()->set_text (patch_name);
+ p->set_text (patch_name);
p->show();
}
}
if (have_periodic_system_messages) {
- double zoom = trackview.editor().get_current_zoom (); // frames per pixel
+ double zoom = trackview.editor().get_current_zoom (); // samples per pixel
/* get an approximate value for the number of samples per video frame */
- double video_frame = trackview.session()->frame_rate() * (1.0/30);
+ double video_frame = trackview.session()->sample_rate() * (1.0/30);
/* if we are zoomed out beyond than the cutoff (i.e. more
- * frames per pixel than frames per 4 video frames), don't
+ * samples per pixel than samples per 4 video frames), don't
* show periodic sysex messages.
*/
}
for (MidiModel::SysExes::const_iterator i = _model->sysexes().begin(); i != _model->sysexes().end(); ++i) {
- Evoral::Beats time = (*i)->time();
+ MidiModel::SysExPtr sysex_ptr = *i;
+ Temporal::Beats time = sysex_ptr->time();
if ((*i)->is_spp() || (*i)->is_mtc_quarter() || (*i)->is_mtc_full()) {
if (!display_periodic_messages) {
}
string text = str.str();
- const double x = trackview.editor().sample_to_pixel(source_beats_to_region_frames(time));
+ const double x = trackview.editor().sample_to_pixel(source_beats_to_region_samples(time));
double height = midi_stream_view()->contents_height();
// CAIROCANVAS: no longer passing *i (the sysex event) to the
// SysEx canvas object!!!
+ boost::shared_ptr<SysEx> sysex = find_canvas_sys_ex (sysex_ptr);
- boost::shared_ptr<SysEx> sysex = boost::shared_ptr<SysEx>(
- new SysEx (*this, _note_group, text, height, x, 1.0));
-
- // Show unless message is beyond the region bounds
- if (time - _region->start() >= _region->length() || time < _region->start()) {
- sysex->hide();
+ if (!sysex) {
+ sysex = boost::shared_ptr<SysEx>(
+ new SysEx (*this, _note_group, text, height, x, 1.0, sysex_ptr));
+ _sys_exes.insert (make_pair (sysex_ptr, sysex));
} else {
- sysex->show();
+ sysex->set_height (height);
+ sysex->item().set_position (ArdourCanvas::Duple (x, 1.0));
}
- _sys_exes.push_back(sysex);
+ // Show unless message is beyond the region bounds
+// XXX REQUIRES APPROPRIATE OPERATORS FOR Temporal::Beats and samplepos? say what?
+#warning paul fix this
+// if (time - _region->start() >= _region->length() || time < _region->start()) {
+// sysex->hide();
+// } else {
+// sysex->show();
+// }
}
}
bool hide_all = false;
PatchChanges::iterator x = _patch_changes.begin();
if (x != _patch_changes.end()) {
- hide_all = (*x).second->flag()->width() >= _pixel_width;
+ hide_all = x->second->width() >= _pixel_width;
}
if (hide_all) {
for (; x != _patch_changes.end(); ++x) {
- (*x).second->hide();
+ x->second->hide();
}
}
ghost->set_duration (_region->length() / samples_per_pixel);
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- ghost->add_note(*i);
+ ghost->add_note(i->second);
}
ghosts.push_back (ghost);
-
+ enable_display (true);
return ghost;
}
/** Resolve an active MIDI note (while recording).
*/
void
-MidiRegionView::resolve_note(uint8_t note, Evoral::Beats end_time)
+MidiRegionView::resolve_note(uint8_t note, Temporal::Beats end_time)
{
if (midi_view()->note_mode() != Sustained) {
return;
end_time - _active_notes[note]->note()->time());
/* End time is relative to the region being recorded. */
- const framepos_t end_time_frames = region_beats_to_region_frames(end_time);
+ const samplepos_t end_time_samples = region_beats_to_region_samples(end_time);
- _active_notes[note]->set_x1 (trackview.editor().sample_to_pixel(end_time_frames));
+ _active_notes[note]->set_x1 (trackview.editor().sample_to_pixel(end_time_samples));
_active_notes[note]->set_outline_all ();
_active_notes[note] = 0;
}
boost::shared_ptr<NoteType> note = ev->note();
const double session_source_start = _region->quarter_note() - mr->start_beats();
- const framepos_t note_start_frames = map.frame_at_quarter_note (note->time().to_double() + session_source_start) - _region->position();
+ const samplepos_t note_start_samples = map.sample_at_quarter_note (note->time().to_double() + session_source_start) - _region->position();
- const double x0 = trackview.editor().sample_to_pixel (note_start_frames);
+ const double x0 = trackview.editor().sample_to_pixel (note_start_samples);
double x1;
const double y0 = 1 + floor(note_to_y(note->note()));
double y1;
note_end_time = mr->start_beats() + mr->length_beats();
}
- const framepos_t note_end_frames = map.frame_at_quarter_note (session_source_start + note_end_time) - _region->position();
+ const samplepos_t note_end_samples = map.sample_at_quarter_note (session_source_start + note_end_time) - _region->position();
- x1 = std::max(1., trackview.editor().sample_to_pixel (note_end_frames)) - 1;
+ x1 = std::max(1., trackview.editor().sample_to_pixel (note_end_samples)) - 1;
} else {
x1 = std::max(1., trackview.editor().sample_to_pixel (_region->length())) - 1;
}
y1 = y0 + std::max(1., floor(note_height()) - 1);
ev->set (ArdourCanvas::Rect (x0, y0, x1, y1));
+ ev->set_velocity (note->velocity()/127.0);
if (!note->length()) {
if (_active_notes && note->note() < 128) {
boost::shared_ptr<NoteType> note = ev->note();
const double note_time_qn = note->time().to_double() + (_region->quarter_note() - midi_region()->start_beats());
- const framepos_t note_start_frames = trackview.session()->tempo_map().frame_at_quarter_note (note_time_qn) - _region->position();
+ const samplepos_t note_start_samples = trackview.session()->tempo_map().sample_at_quarter_note (note_time_qn) - _region->position();
- const double x = trackview.editor().sample_to_pixel(note_start_frames);
+ const double x = trackview.editor().sample_to_pixel(note_start_samples);
const double diamond_size = std::max(1., floor(note_height()) - 2.);
const double y = 1.5 + floor(note_to_y(note->note())) + diamond_size * .5;
if (midi_view()->note_mode() == Sustained) {
- Note* ev_rect = new Note (*this, _note_group, note);
+ Note* ev_rect = new Note (*this, _note_group, note); // XXX may leak
update_sustained (ev_rect);
const double diamond_size = std::max(1., floor(note_height()) - 2.);
- Hit* ev_diamond = new Hit (*this, _note_group, diamond_size, note);
+ Hit* ev_diamond = new Hit (*this, _note_group, diamond_size, note); // XXX may leak
update_hit (ev_diamond);
}
event->on_channel_selection_change (get_selected_channels());
- _events.push_back(event);
+ _events.insert (make_pair (event->note(), event));
if (visible) {
event->show();
void
MidiRegionView::step_add_note (uint8_t channel, uint8_t number, uint8_t velocity,
- Evoral::Beats pos, Evoral::Beats len)
+ Temporal::Beats pos, Temporal::Beats len)
{
boost::shared_ptr<NoteType> new_note (new NoteType (channel, pos, len, number, velocity));
/* potentially extend region to hold new note */
- framepos_t end_frame = source_beats_to_absolute_frames (new_note->end_time());
- framepos_t region_end = _region->last_frame();
+ samplepos_t end_sample = source_beats_to_absolute_samples (new_note->end_time());
+ samplepos_t region_end = _region->last_sample();
- if (end_frame > region_end) {
+ if (end_sample > region_end) {
/* XX sets length in beats from audio space. make musical */
- _region->set_length (end_frame - _region->position(), 0);
+ _region->set_length (end_sample - _region->position(), 0);
}
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
}
void
-MidiRegionView::step_sustain (Evoral::Beats beats)
+MidiRegionView::step_sustain (Temporal::Beats beats)
{
change_note_lengths (false, false, beats, false, true);
}
void
MidiRegionView::add_canvas_patch_change (MidiModel::PatchChangePtr patch, const string& displaytext, bool /*active_channel*/)
{
- framecnt_t region_frames = source_beats_to_region_frames (patch->time());
- const double x = trackview.editor().sample_to_pixel (region_frames);
+ samplecnt_t region_samples = source_beats_to_region_samples (patch->time());
+ const double x = trackview.editor().sample_to_pixel (region_samples);
double const height = midi_stream_view()->contents_height();
if (patch_change->item().width() < _pixel_width) {
// Show unless patch change is beyond the region bounds
- if (region_frames < 0 || region_frames >= _region->length()) {
+ if (region_samples < 0 || region_samples >= _region->length()) {
patch_change->hide();
} else {
patch_change->show();
/// Return true iff @p pc applies to the given time on the given channel.
static bool
-patch_applies (const ARDOUR::MidiModel::constPatchChangePtr pc, Evoral::Beats time, uint8_t channel)
+patch_applies (const ARDOUR::MidiModel::constPatchChangePtr pc, Temporal::Beats time, uint8_t channel)
{
return pc->time() <= time && pc->channel() == channel;
}
void
-MidiRegionView::get_patch_key_at (Evoral::Beats time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const
+MidiRegionView::get_patch_key_at (Temporal::Beats time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const
{
// The earliest event not before time
MidiModel::PatchChanges::iterator i = _model->patch_change_lower_bound (time);
}
void
-MidiRegionView::change_patch_change (MidiModel::PatchChangePtr old_change, const Evoral::PatchChange<Evoral::Beats> & new_change)
+MidiRegionView::change_patch_change (MidiModel::PatchChangePtr old_change, const Evoral::PatchChange<Temporal::Beats> & new_change)
{
string name = _("alter patch change");
trackview.editor().begin_reversible_command (name);
}
/** Add a patch change to the region.
- * @param t Time in frames relative to region position
+ * @param t Time in samples relative to region position
* @param patch Patch to add; time and channel are ignored (time is converted from t, and channel comes from
* MidiTimeAxisView::get_channel_for_add())
*/
void
-MidiRegionView::add_patch_change (framecnt_t t, Evoral::PatchChange<Evoral::Beats> const & patch)
+MidiRegionView::add_patch_change (samplecnt_t t, Evoral::PatchChange<Temporal::Beats> const & patch)
{
- MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
string name = _("add patch change");
trackview.editor().begin_reversible_command (name);
MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (name);
c->add (MidiModel::PatchChangePtr (
- new Evoral::PatchChange<Evoral::Beats> (
- absolute_frames_to_source_beats (_region->position() + t),
- mtv->get_channel_for_add(), patch.program(), patch.bank()
+ new Evoral::PatchChange<Temporal::Beats> (
+ absolute_samples_to_source_beats (_region->position() + t),
+ patch.channel(), patch.program(), patch.bank()
)
)
);
}
void
-MidiRegionView::move_patch_change (PatchChange& pc, Evoral::Beats t)
+MidiRegionView::move_patch_change (PatchChange& pc, Temporal::Beats t)
{
trackview.editor().begin_reversible_command (_("move patch change"));
MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("move patch change"));
clear_editor_note_selection ();
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- add_to_selection (*i);
+ add_to_selection (i->second);
}
}
void
-MidiRegionView::select_range (framepos_t start, framepos_t end)
+MidiRegionView::select_range (samplepos_t start, samplepos_t end)
{
clear_editor_note_selection ();
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- framepos_t t = source_beats_to_absolute_frames((*i)->note()->time());
+ samplepos_t t = source_beats_to_absolute_samples(i->first->time());
if (t >= start && t <= end) {
- add_to_selection (*i);
+ add_to_selection (i->second);
}
}
}
MidiRegionView::invert_selection ()
{
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if ((*i)->selected()) {
- remove_from_selection(*i);
+ if (i->second->selected()) {
+ remove_from_selection(i->second);
} else {
- add_to_selection (*i);
+ add_to_selection (i->second);
}
}
}
} else {
/* find end of latest note selected, select all between that and the start of "ev" */
- Evoral::Beats earliest = Evoral::MaxBeats;
- Evoral::Beats latest = Evoral::Beats();
+ Temporal::Beats earliest = std::numeric_limits<Temporal::Beats>::max();
+ Temporal::Beats latest = Temporal::Beats();
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
if ((*i)->note()->end_time() > latest) {
/* find notes entirely within OR spanning the earliest..latest range */
- if (((*i)->note()->time() >= earliest && (*i)->note()->end_time() <= latest) ||
- ((*i)->note()->time() <= earliest && (*i)->note()->end_time() >= latest)) {
- add_to_selection (*i);
+ if ((i->first->time() >= earliest && i->first->end_time() <= latest) ||
+ (i->first->time() <= earliest && i->first->end_time() >= latest)) {
+ add_to_selection (i->second);
}
-
}
}
}
}
void
-MidiRegionView::update_drag_selection(framepos_t start, framepos_t end, double gy0, double gy1, bool extend)
+MidiRegionView::update_drag_selection(samplepos_t start, samplepos_t end, double gy0, double gy1, bool extend)
{
PublicEditor& editor = trackview.editor();
// Convert to local coordinates
- const framepos_t p = _region->position();
+ const samplepos_t p = _region->position();
const double y = midi_view()->y_position();
- const double x0 = editor.sample_to_pixel(max((framepos_t)0, start - p));
- const double x1 = editor.sample_to_pixel(max((framepos_t)0, end - p));
+ const double x0 = editor.sample_to_pixel(max((samplepos_t)0, start - p));
+ const double x1 = editor.sample_to_pixel(max((samplepos_t)0, end - p));
const double y0 = max(0.0, gy0 - y);
const double y1 = max(0.0, gy1 - y);
// We probably need a tree to be able to find events in O(log(n)) time.
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if ((*i)->x0() < x1 && (*i)->x1() > x0 && (*i)->y0() < y1 && (*i)->y1() > y0) {
+ if (i->second->x0() < x1 && i->second->x1() > x0 && i->second->y0() < y1 && i->second->y1() > y0) {
// Rectangles intersect
- if (!(*i)->selected()) {
- add_to_selection (*i);
+ if (!i->second->selected()) {
+ add_to_selection (i->second);
}
- } else if ((*i)->selected() && !extend) {
+ } else if (i->second->selected() && !extend) {
// Rectangles do not intersect
- remove_from_selection (*i);
+ remove_from_selection (i->second);
}
}
// We probably need a tree to be able to find events in O(log(n)) time.
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if (((*i)->y1() >= y1 && (*i)->y1() <= y2)) {
+ if ((i->second->y1() >= y1 && i->second->y1() <= y2)) {
// within y- (note-) range
- if (!(*i)->selected()) {
- add_to_selection (*i);
+ if (!i->second->selected()) {
+ add_to_selection (i->second);
}
- } else if ((*i)->selected() && !extend) {
- remove_from_selection (*i);
+ } else if (i->second->selected() && !extend) {
+ remove_from_selection (i->second);
}
}
}
}
}
-void
-MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
+Temporal::Beats
+MidiRegionView::earliest_in_selection ()
{
- typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
- PossibleChord to_play;
- Evoral::Beats earliest = Evoral::MaxBeats;
+ Temporal::Beats earliest = std::numeric_limits<Temporal::Beats>::max();
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
if ((*i)->note()->time() < earliest) {
}
}
+ return earliest;
+}
+
+void
+MidiRegionView::move_selection(double dx_qn, double dy, double cumulative_dy)
+{
+ typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
+ Editor* editor = dynamic_cast<Editor*> (&trackview.editor());
+ TempoMap& tmap (editor->session()->tempo_map());
+ PossibleChord to_play;
+ Temporal::Beats earliest = earliest_in_selection();
+
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
- if ((*i)->note()->time() == earliest) {
- to_play.push_back ((*i)->note());
+ NoteBase* n = *i;
+ if (n->note()->time() == earliest) {
+ to_play.push_back (n->note());
}
+ double const note_time_qn = session_relative_qn (n->note()->time().to_double());
+ double dx = 0.0;
+ if (midi_view()->note_mode() == Sustained) {
+ dx = editor->sample_to_pixel_unrounded (tmap.sample_at_quarter_note (note_time_qn + dx_qn))
+ - n->item()->item_to_canvas (ArdourCanvas::Duple (n->x0(), 0)).x;
+ } else {
+ /* Hit::x0() is offset by _position.x, unlike Note::x0() */
+ Hit* hit = dynamic_cast<Hit*>(n);
+ if (hit) {
+ dx = editor->sample_to_pixel_unrounded (tmap.sample_at_quarter_note (note_time_qn + dx_qn))
+ - n->item()->item_to_canvas (ArdourCanvas::Duple (((hit->x0() + hit->x1()) / 2.0) - hit->position().x, 0)).x;
+ }
+ }
+
(*i)->move_event(dx, dy);
+
+ /* update length */
+ if (midi_view()->note_mode() == Sustained) {
+ Note* sus = dynamic_cast<Note*> (*i);
+ double const len_dx = editor->sample_to_pixel_unrounded (
+ tmap.sample_at_quarter_note (note_time_qn + dx_qn + n->note()->length().to_double()));
+
+ sus->set_x1 (n->item()->canvas_to_item (ArdourCanvas::Duple (len_dx, 0)).x);
+ }
}
if (dy && !_selection.empty() && !_no_sound_notes && UIConfiguration::instance().get_sound_midi_notes()) {
}
}
+NoteBase*
+MidiRegionView::copy_selection (NoteBase* primary)
+{
+ _copy_drag_events.clear ();
+
+ if (_selection.empty()) {
+ return 0;
+ }
+
+ NoteBase* note;
+ NoteBase* ret = 0;
+
+ for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+ boost::shared_ptr<NoteType> g (new NoteType (*((*i)->note())));
+ if (midi_view()->note_mode() == Sustained) {
+ Note* n = new Note (*this, _note_group, g);
+ update_sustained (n, false);
+ note = n;
+ } else {
+ Hit* h = new Hit (*this, _note_group, 10, g);
+ update_hit (h, false);
+ note = h;
+ }
+
+ if ((*i) == primary) {
+ ret = note;
+ }
+
+ _copy_drag_events.push_back (note);
+ }
+
+ return ret;
+}
+
+void
+MidiRegionView::move_copies (double dx_qn, double dy, double cumulative_dy)
+{
+ typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
+ Editor* editor = dynamic_cast<Editor*> (&trackview.editor());
+ TempoMap& tmap (editor->session()->tempo_map());
+ PossibleChord to_play;
+ Temporal::Beats earliest = earliest_in_selection();
+
+ for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end(); ++i) {
+ NoteBase* n = *i;
+ if (n->note()->time() == earliest) {
+ to_play.push_back (n->note());
+ }
+ double const note_time_qn = session_relative_qn (n->note()->time().to_double());
+ double dx = 0.0;
+ if (midi_view()->note_mode() == Sustained) {
+ dx = editor->sample_to_pixel_unrounded (tmap.sample_at_quarter_note (note_time_qn + dx_qn))
+ - n->item()->item_to_canvas (ArdourCanvas::Duple (n->x0(), 0)).x;
+ } else {
+ Hit* hit = dynamic_cast<Hit*>(n);
+ if (hit) {
+ dx = editor->sample_to_pixel_unrounded (tmap.sample_at_quarter_note (note_time_qn + dx_qn))
+ - n->item()->item_to_canvas (ArdourCanvas::Duple (((hit->x0() + hit->x1()) / 2.0) - hit->position().x, 0)).x;
+ }
+ }
+
+ (*i)->move_event(dx, dy);
+
+ if (midi_view()->note_mode() == Sustained) {
+ Note* sus = dynamic_cast<Note*> (*i);
+ double const len_dx = editor->sample_to_pixel_unrounded (
+ tmap.sample_at_quarter_note (note_time_qn + dx_qn + n->note()->length().to_double()));
+
+ sus->set_x1 (n->item()->canvas_to_item (ArdourCanvas::Duple (len_dx, 0)).x);
+ }
+ }
+
+ if (dy && !_copy_drag_events.empty() && !_no_sound_notes && UIConfiguration::instance().get_sound_midi_notes()) {
+
+ if (to_play.size() > 1) {
+
+ PossibleChord shifted;
+
+ for (PossibleChord::iterator n = to_play.begin(); n != to_play.end(); ++n) {
+ boost::shared_ptr<NoteType> moved_note (new NoteType (**n));
+ moved_note->set_note (moved_note->note() + cumulative_dy);
+ shifted.push_back (moved_note);
+ }
+
+ start_playing_midi_chord (shifted);
+
+ } else if (!to_play.empty()) {
+
+ boost::shared_ptr<NoteType> moved_note (new NoteType (*to_play.front()));
+ moved_note->set_note (moved_note->note() + cumulative_dy);
+ start_playing_midi_note (moved_note);
+ }
+ }
+}
+
void
-MidiRegionView::note_dropped(NoteBase *, frameoffset_t dt, int8_t dnote)
+MidiRegionView::note_dropped(NoteBase *, double d_qn, int8_t dnote, bool copy)
{
uint8_t lowest_note_in_selection = 127;
uint8_t highest_note_in_selection = 0;
uint8_t highest_note_difference = 0;
- // find highest and lowest notes first
+ if (!copy) {
+ // find highest and lowest notes first
- for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
- uint8_t pitch = (*i)->note()->note();
- lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
- highest_note_in_selection = std::max(highest_note_in_selection, pitch);
- }
-
- /*
- cerr << "dnote: " << (int) dnote << endl;
- cerr << "lowest note (streamview): " << int(midi_stream_view()->lowest_note())
- << " highest note (streamview): " << int(midi_stream_view()->highest_note()) << endl;
- cerr << "lowest note (selection): " << int(lowest_note_in_selection) << " highest note(selection): "
- << int(highest_note_in_selection) << endl;
- cerr << "selection size: " << _selection.size() << endl;
- cerr << "Highest note in selection: " << (int) highest_note_in_selection << endl;
- */
+ for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+ uint8_t pitch = (*i)->note()->note();
+ lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
+ highest_note_in_selection = std::max(highest_note_in_selection, pitch);
+ }
- // Make sure the note pitch does not exceed the MIDI standard range
- if (highest_note_in_selection + dnote > 127) {
- highest_note_difference = highest_note_in_selection - 127;
- }
- TempoMap& map (trackview.session()->tempo_map());
+ /*
+ cerr << "dnote: " << (int) dnote << endl;
+ cerr << "lowest note (streamview): " << int(midi_stream_view()->lowest_note())
+ << " highest note (streamview): " << int(midi_stream_view()->highest_note()) << endl;
+ cerr << "lowest note (selection): " << int(lowest_note_in_selection) << " highest note(selection): "
+ << int(highest_note_in_selection) << endl;
+ cerr << "selection size: " << _selection.size() << endl;
+ cerr << "Highest note in selection: " << (int) highest_note_in_selection << endl;
+ */
+
+ // Make sure the note pitch does not exceed the MIDI standard range
+ if (highest_note_in_selection + dnote > 127) {
+ highest_note_difference = highest_note_in_selection - 127;
+ }
- start_note_diff_command (_("move notes"));
+ start_note_diff_command (_("move notes"));
- for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) {
+ for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) {
- double const start_qn = _region->quarter_note() - midi_region()->start_beats();
- framepos_t new_frames = map.frame_at_quarter_note (start_qn + (*i)->note()->time().to_double()) + dt;
- Evoral::Beats new_time = Evoral::Beats (map.quarter_note_at_frame (new_frames) - start_qn);
- if (new_time < 0) {
- continue;
+ Temporal::Beats new_time = Temporal::Beats ((*i)->note()->time().to_double() + d_qn);
+
+ if (new_time < 0) {
+ continue;
+ }
+
+ note_diff_add_change (*i, MidiModel::NoteDiffCommand::StartTime, new_time);
+
+ uint8_t original_pitch = (*i)->note()->note();
+ uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
+
+ // keep notes in standard midi range
+ clamp_to_0_127(new_pitch);
+
+ lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
+ highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
+
+ note_diff_add_change (*i, MidiModel::NoteDiffCommand::NoteNumber, new_pitch);
+ }
+ } else {
+
+ clear_editor_note_selection ();
+
+ for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end(); ++i) {
+ uint8_t pitch = (*i)->note()->note();
+ lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
+ highest_note_in_selection = std::max(highest_note_in_selection, pitch);
}
- note_diff_add_change (*i, MidiModel::NoteDiffCommand::StartTime, new_time);
+ // Make sure the note pitch does not exceed the MIDI standard range
+ if (highest_note_in_selection + dnote > 127) {
+ highest_note_difference = highest_note_in_selection - 127;
+ }
+
+ start_note_diff_command (_("copy notes"));
+
+ for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end() ; ++i) {
+
+ /* update time */
+ Temporal::Beats new_time = Temporal::Beats ((*i)->note()->time().to_double() + d_qn);
+
+ if (new_time < 0) {
+ continue;
+ }
+
+ (*i)->note()->set_time (new_time);
+
+ /* update pitch */
+
+ uint8_t original_pitch = (*i)->note()->note();
+ uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
+
+ (*i)->note()->set_note (new_pitch);
- uint8_t original_pitch = (*i)->note()->note();
- uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
+ // keep notes in standard midi range
+ clamp_to_0_127(new_pitch);
- // keep notes in standard midi range
- clamp_to_0_127(new_pitch);
+ lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
+ highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
- lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
- highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
+ note_diff_add_note ((*i)->note(), true);
- note_diff_add_change (*i, MidiModel::NoteDiffCommand::NoteNumber, new_pitch);
+ delete *i;
+ }
+
+ _copy_drag_events.clear ();
}
- apply_diff();
+ apply_diff (false, copy);
// 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()) {
- midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
+ midi_stream_view()->set_note_range (MidiStreamView::ContentsRange);
}
}
/** @param x Pixel relative to the region position.
* @param ensure_snap defaults to false. true = snap always, ignoring snap mode and magnetic snap.
* Used for inverting the snap logic with key modifiers and snap delta calculation.
- * @return Snapped frame relative to the region position.
+ * @return Snapped sample relative to the region position.
*/
-framepos_t
+samplepos_t
MidiRegionView::snap_pixel_to_sample(double x, bool ensure_snap)
{
PublicEditor& editor (trackview.editor());
- return snap_frame_to_frame (editor.pixel_to_sample (x), ensure_snap);
+ return snap_sample_to_sample (editor.pixel_to_sample (x), ensure_snap).sample;
}
/** @param x Pixel relative to the region position.
double
MidiRegionView::get_position_pixels()
{
- framepos_t region_frame = get_position();
- return trackview.editor().sample_to_pixel(region_frame);
+ samplepos_t region_sample = get_position();
+ return trackview.editor().sample_to_pixel(region_sample);
}
double
MidiRegionView::get_end_position_pixels()
{
- framepos_t frame = get_position() + get_duration ();
- return trackview.editor().sample_to_pixel(frame);
+ samplepos_t sample = get_position() + get_duration ();
+ return trackview.editor().sample_to_pixel(sample);
}
-framepos_t
-MidiRegionView::source_beats_to_absolute_frames(Evoral::Beats beats) const
+samplepos_t
+MidiRegionView::source_beats_to_absolute_samples(Temporal::Beats beats) const
{
- /* the time converter will return the frame corresponding to `beats'
+ /* the time converter will return the sample corresponding to `beats'
relative to the start of the source. The start of the source
is an implied position given by region->position - region->start
*/
- const framepos_t source_start = _region->position() - _region->start();
+ const samplepos_t source_start = _region->position() - _region->start();
return source_start + _source_relative_time_converter.to (beats);
}
-Evoral::Beats
-MidiRegionView::absolute_frames_to_source_beats(framepos_t frames) const
+Temporal::Beats
+MidiRegionView::absolute_samples_to_source_beats(samplepos_t samples) const
{
- /* the `frames' argument needs to be converted into a frame count
+ /* the `samples' argument needs to be converted into a sample count
relative to the start of the source before being passed in to the
converter.
*/
- const framepos_t source_start = _region->position() - _region->start();
- return _source_relative_time_converter.from (frames - source_start);
+ const samplepos_t source_start = _region->position() - _region->start();
+ return _source_relative_time_converter.from (samples - source_start);
}
-framepos_t
-MidiRegionView::region_beats_to_region_frames(Evoral::Beats beats) const
+samplepos_t
+MidiRegionView::region_beats_to_region_samples(Temporal::Beats beats) const
{
return _region_relative_time_converter.to(beats);
}
-Evoral::Beats
-MidiRegionView::region_frames_to_region_beats(framepos_t frames) const
+Temporal::Beats
+MidiRegionView::region_samples_to_region_beats(samplepos_t samples) const
{
- return _region_relative_time_converter.from(frames);
+ return _region_relative_time_converter.from(samples);
}
double
-MidiRegionView::region_frames_to_region_beats_double (framepos_t frames) const
+MidiRegionView::region_samples_to_region_beats_double (samplepos_t samples) const
{
- return _region_relative_time_converter_double.from(frames);
+ return _region_relative_time_converter_double.from(samples);
}
void
ArdourCanvas::Rect (note->x0(), note->y0(), note->x0(), note->y1()));
// calculate the colors: get the color settings
- uint32_t fill_color = UINT_RGBA_CHANGE_A(
- UIConfiguration::instance().color ("midi note selected"),
- 128);
+ uint32_t fill_color = NoteBase::meter_style_fill_color (note->note()->velocity(), true);
// make the resize preview notes more transparent and bright
fill_color = UINT_INTERPOLATE(fill_color, 0xFFFFFF40, 0.5);
0.85));
resize_rect->set_outline_color (NoteBase::calculate_outline (
- UIConfiguration::instance().color ("midi note selected")));
+ UIConfiguration::instance().color ("midi note selected outline")));
resize_data->resize_rect = resize_rect;
_resize_data.push_back(resize_data);
}
if (current_x < 0) {
- // This works even with snapping because RegionView::snap_frame_to_frame()
+ // This works even with snapping because RegionView::snap_sample_to_sample()
// snaps forward if the snapped sample is before the beginning of the region
current_x = 0;
}
if (!cursor_set) {
/* Convert snap delta from pixels to beats. */
- framepos_t snap_delta_samps = trackview.editor().pixel_to_sample (snap_delta);
+ samplepos_t snap_delta_samps = trackview.editor().pixel_to_sample (snap_delta);
double snap_delta_beats = 0.0;
int sign = 1;
/* negative beat offsets aren't allowed */
if (snap_delta_samps > 0) {
- snap_delta_beats = region_frames_to_region_beats_double (snap_delta_samps);
+ snap_delta_beats = region_samples_to_region_beats_double (snap_delta_samps);
} else if (snap_delta_samps < 0) {
- snap_delta_beats = region_frames_to_region_beats_double ( - snap_delta_samps);
+ snap_delta_beats = region_samples_to_region_beats_double ( - snap_delta_samps);
sign = -1;
}
} else {
snapped_x = trackview.editor ().pixel_to_sample (current_x);
}
- const Evoral::Beats beats = Evoral::Beats (tmap.exact_beat_at_frame (snapped_x + midi_region()->position(), divisions)
+
+ const Temporal::Beats beats = Temporal::Beats (tmap.exact_beat_at_sample (snapped_x + midi_region()->position(), divisions)
- midi_region()->beat()) + midi_region()->start_beats();
- Evoral::Beats len = Evoral::Beats();
+ Temporal::Beats len = Temporal::Beats();
if (at_front) {
if (beats < canvas_note->note()->end_time()) {
}
}
- len = std::max(Evoral::Beats(1 / 512.0), len);
+ len = std::max(Temporal::Beats(1 / 512.0), len);
char buf[16];
snprintf (buf, sizeof (buf), "%.3g beats", len.to_double());
show_verbose_cursor (buf, 0, 0);
cursor_set = true;
+
+ trackview.editor().set_snapped_cursor_position ( snapped_x + midi_region()->position() );
}
}
}
/* Convert snap delta from pixels to beats with sign. */
- framepos_t snap_delta_samps = trackview.editor().pixel_to_sample (snap_delta);
+ samplepos_t snap_delta_samps = trackview.editor().pixel_to_sample (snap_delta);
double snap_delta_beats = 0.0;
int sign = 1;
if (snap_delta_samps > 0) {
- snap_delta_beats = region_frames_to_region_beats_double (snap_delta_samps);
+ snap_delta_beats = region_samples_to_region_beats_double (snap_delta_samps);
} else if (snap_delta_samps < 0) {
- snap_delta_beats = region_frames_to_region_beats_double ( - snap_delta_samps);
+ snap_delta_beats = region_samples_to_region_beats_double ( - snap_delta_samps);
sign = -1;
}
uint32_t divisions = 0;
- /* Convert the new x position to a frame within the source */
- framepos_t current_fr;
+ /* Convert the new x position to a sample within the source */
+ samplepos_t current_fr;
if (with_snap) {
current_fr = snap_pixel_to_sample (current_x, ensure_snap);
divisions = trackview.editor().get_grid_music_divisions (0);
}
/* and then to beats */
- const double e_qaf = tmap.exact_qn_at_frame (current_fr + midi_region()->position(), divisions);
+ const double e_qaf = tmap.exact_qn_at_sample (current_fr + midi_region()->position(), divisions);
const double quarter_note_start = _region->quarter_note() - midi_region()->start_beats();
- const Evoral::Beats x_beats = Evoral::Beats (e_qaf - quarter_note_start);
+ const Temporal::Beats x_beats = Temporal::Beats (e_qaf - quarter_note_start);
if (at_front && x_beats < canvas_note->note()->end_time()) {
note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::StartTime, x_beats - (sign * snap_delta_beats));
- Evoral::Beats len = canvas_note->note()->time() - x_beats + (sign * snap_delta_beats);
+ Temporal::Beats len = canvas_note->note()->time() - x_beats + (sign * snap_delta_beats);
len += canvas_note->note()->length();
if (!!len) {
}
if (!at_front) {
- Evoral::Beats len = std::max(Evoral::Beats(1 / 512.0),
+ Temporal::Beats len = std::max(Temporal::Beats(1 / 512.0),
x_beats - canvas_note->note()->time() - (sign * snap_delta_beats));
note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::Length, len);
}
}
void
-MidiRegionView::trim_note (NoteBase* event, Evoral::Beats front_delta, Evoral::Beats end_delta)
+MidiRegionView::trim_note (NoteBase* event, Temporal::Beats front_delta, Temporal::Beats end_delta)
{
bool change_start = false;
bool change_length = false;
- Evoral::Beats new_start;
- Evoral::Beats new_length;
+ Temporal::Beats new_start;
+ Temporal::Beats new_length;
/* NOTE: the semantics of the two delta arguments are slightly subtle:
if (front_delta < 0) {
if (event->note()->time() < -front_delta) {
- new_start = Evoral::Beats();
+ new_start = Temporal::Beats();
} else {
new_start = event->note()->time() + front_delta; // moves earlier
}
} else {
- Evoral::Beats new_pos = event->note()->time() + front_delta;
+ Temporal::Beats new_pos = event->note()->time() + front_delta;
if (new_pos < event->note()->end_time()) {
new_start = event->note()->time() + front_delta;
}
void
-MidiRegionView::change_note_time (NoteBase* event, Evoral::Beats delta, bool relative)
+MidiRegionView::change_note_time (NoteBase* event, Temporal::Beats delta, bool relative)
{
- Evoral::Beats new_time;
+ Temporal::Beats new_time;
if (relative) {
if (delta < 0.0) {
if (event->note()->time() < -delta) {
- new_time = Evoral::Beats();
+ new_time = Temporal::Beats();
} else {
new_time = event->note()->time() + delta;
}
}
void
-MidiRegionView::change_note_length (NoteBase* event, Evoral::Beats t)
+MidiRegionView::change_note_length (NoteBase* event, Temporal::Beats t)
{
note_diff_add_change (event, MidiModel::NoteDiffCommand::Length, t);
}
}
void
-MidiRegionView::change_note_lengths (bool fine, bool shorter, Evoral::Beats delta, bool start, bool end)
+MidiRegionView::change_note_lengths (bool fine, bool shorter, Temporal::Beats delta, bool start, bool end)
{
if (!delta) {
if (fine) {
- delta = Evoral::Beats(1.0/128.0);
+ delta = Temporal::Beats(1.0/128.0);
} else {
/* grab the current grid distance */
delta = get_grid_beats(_region->position());
/* note the negation of the delta for start */
trim_note (*i,
- (start ? -delta : Evoral::Beats()),
- (end ? delta : Evoral::Beats()));
+ (start ? -delta : Temporal::Beats()),
+ (end ? delta : Temporal::Beats()));
i = next;
}
into a vector and sort before using the first one.
*/
- const framepos_t ref_point = source_beats_to_absolute_frames ((*(_selection.begin()))->note()->time());
- Evoral::Beats delta;
+ const samplepos_t ref_point = source_beats_to_absolute_samples ((*(_selection.begin()))->note()->time());
+ Temporal::Beats delta;
if (!fine) {
/* non-fine, move by 1 bar regardless of snap */
- delta = Evoral::Beats(trackview.session()->tempo_map().meter_at_frame (ref_point).divisions_per_bar());
+ delta = Temporal::Beats(trackview.session()->tempo_map().meter_at_sample (ref_point).divisions_per_bar());
} else if (trackview.editor().snap_mode() == Editing::SnapOff) {
/* grid is off - use nudge distance */
- framepos_t unused;
- const framecnt_t distance = trackview.editor().get_nudge_distance (ref_point, unused);
- delta = region_frames_to_region_beats (fabs ((double)distance));
+ samplepos_t unused;
+ const samplecnt_t distance = trackview.editor().get_nudge_distance (ref_point, unused);
+ delta = region_samples_to_region_beats (fabs ((double)distance));
} else {
/* use grid */
- framepos_t next_pos = ref_point;
-
+ MusicSample next_pos (ref_point, 0);
if (forward) {
- if (max_framepos - 1 < next_pos) {
- next_pos += 1;
+ if (max_samplepos - 1 < next_pos.sample) {
+ next_pos.sample += 1;
}
} else {
- if (next_pos == 0) {
+ if (next_pos.sample == 0) {
return;
}
- next_pos -= 1;
+ next_pos.sample -= 1;
}
- trackview.editor().snap_to (next_pos, (forward ? RoundUpAlways : RoundDownAlways), false);
- const framecnt_t distance = ref_point - next_pos;
- delta = region_frames_to_region_beats (fabs ((double)distance));
+ trackview.editor().snap_to (next_pos, (forward ? RoundUpAlways : RoundDownAlways), SnapToGrid_Unscaled, false);
+ const samplecnt_t distance = ref_point - next_pos.sample;
+ delta = region_samples_to_region_beats (fabs ((double)distance));
}
if (!delta) {
// Update notes for selection
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- (*i)->on_channel_selection_change (mask);
+ i->second->on_channel_selection_change (mask);
}
_patch_changes.clear ();
/** This method handles undo */
bool
-MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx, const int32_t sub_num)
+MidiRegionView::paste (samplepos_t pos, const ::Selection& selection, PasteContext& ctx, const int32_t sub_num)
{
bool commit = false;
// Paste notes, if available
/** This method handles undo */
void
-MidiRegionView::paste_internal (framepos_t pos, unsigned paste_count, float times, const MidiCutBuffer& mcb)
+MidiRegionView::paste_internal (samplepos_t pos, unsigned paste_count, float times, const MidiCutBuffer& mcb)
{
if (mcb.empty()) {
return;
start_note_diff_command (_("paste"));
- const Evoral::Beats snap_beats = get_grid_beats(pos);
- const Evoral::Beats first_time = (*mcb.notes().begin())->time();
- const Evoral::Beats last_time = (*mcb.notes().rbegin())->end_time();
- const Evoral::Beats duration = last_time - first_time;
- const Evoral::Beats snap_duration = duration.snap_to(snap_beats);
- const Evoral::Beats paste_offset = snap_duration * paste_count;
- const Evoral::Beats quarter_note = absolute_frames_to_source_beats(pos) + paste_offset;
- Evoral::Beats end_point = Evoral::Beats();
+ const Temporal::Beats snap_beats = get_grid_beats(pos);
+ const Temporal::Beats first_time = (*mcb.notes().begin())->time();
+ const Temporal::Beats last_time = (*mcb.notes().rbegin())->end_time();
+ const Temporal::Beats duration = last_time - first_time;
+ const Temporal::Beats snap_duration = duration.snap_to(snap_beats);
+ const Temporal::Beats paste_offset = snap_duration * paste_count;
+ const Temporal::Beats quarter_note = absolute_samples_to_source_beats(pos) + paste_offset;
+ Temporal::Beats end_point = Temporal::Beats();
DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste data spans from %1 to %2 (%3) ; paste pos beats = %4 (based on %5 - %6)\n",
first_time,
/* if we pasted past the current end of the region, extend the region */
- framepos_t end_frame = source_beats_to_absolute_frames (end_point);
- framepos_t region_end = _region->position() + _region->length() - 1;
+ samplepos_t end_sample = source_beats_to_absolute_samples (end_point);
+ samplepos_t region_end = _region->position() + _region->length() - 1;
- if (end_frame > region_end) {
+ if (end_sample > region_end) {
- DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste extended region from %1 to %2\n", region_end, end_frame));
+ DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste extended region from %1 to %2\n", region_end, end_sample));
_region->clear_changes ();
/* we probably need to get the snap modifier somehow to make this correct for non-musical use */
- _region->set_length (end_frame - _region->position(), trackview.editor().get_grid_music_divisions (0));
+ _region->set_length (end_sample - _region->position(), trackview.editor().get_grid_music_divisions (0));
trackview.session()->add_command (new StatefulDiffCommand (_region));
}
}
};
-void
-MidiRegionView::time_sort_events ()
-{
- if (!_sort_needed) {
- return;
- }
-
- EventNoteTimeEarlyFirstComparator cmp;
- _events.sort (cmp);
-
- _sort_needed = false;
-}
-
void
MidiRegionView::goto_next_note (bool add_to_selection)
{
bool use_next = false;
- if (_events.back()->selected()) {
- return;
- }
-
- time_sort_events ();
-
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
uint16_t const channel_mask = mtv->midi_track()->get_playback_channel_mask();
+ NoteBase* first_note = 0;
- for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if ((*i)->selected()) {
- use_next = true;
- continue;
- } else if (use_next) {
- if (channel_mask & (1 << (*i)->note()->channel())) {
- if (!add_to_selection) {
- unique_select (*i);
- } else {
- note_selected (*i, true, false);
+ MidiModel::ReadLock lock(_model->read_lock());
+ MidiModel::Notes& notes (_model->notes());
+
+ for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) {
+ NoteBase* cne = 0;
+ if ((cne = find_canvas_note (*n))) {
+
+ if (!first_note && (channel_mask & (1 << (*n)->channel()))) {
+ first_note = cne;
+ }
+
+ if (cne->selected()) {
+ use_next = true;
+ continue;
+ } else if (use_next) {
+ if (channel_mask & (1 << (*n)->channel())) {
+ if (!add_to_selection) {
+ unique_select (cne);
+ } else {
+ note_selected (cne, true, false);
+ }
+
+ return;
}
- return;
}
}
}
/* use the first one */
- if (!_events.empty() && (channel_mask & (1 << _events.front()->note()->channel ()))) {
- unique_select (_events.front());
+ if (!_events.empty() && first_note) {
+ unique_select (first_note);
}
}
{
bool use_next = false;
- if (_events.front()->selected()) {
- return;
- }
-
- time_sort_events ();
-
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
uint16_t const channel_mask = mtv->midi_track()->get_playback_channel_mask ();
+ NoteBase* last_note = 0;
- for (Events::reverse_iterator i = _events.rbegin(); i != _events.rend(); ++i) {
- if ((*i)->selected()) {
- use_next = true;
- continue;
- } else if (use_next) {
- if (channel_mask & (1 << (*i)->note()->channel())) {
- if (!add_to_selection) {
- unique_select (*i);
- } else {
- note_selected (*i, true, false);
+ MidiModel::ReadLock lock(_model->read_lock());
+ MidiModel::Notes& notes (_model->notes());
+
+ for (MidiModel::Notes::reverse_iterator n = notes.rbegin(); n != notes.rend(); ++n) {
+ NoteBase* cne = 0;
+ if ((cne = find_canvas_note (*n))) {
+
+ if (!last_note && (channel_mask & (1 << (*n)->channel()))) {
+ last_note = cne;
+ }
+
+ if (cne->selected()) {
+ use_next = true;
+ continue;
+
+ } else if (use_next) {
+ if (channel_mask & (1 << (*n)->channel())) {
+ if (!add_to_selection) {
+ unique_select (cne);
+ } else {
+ note_selected (cne, true, false);
+ }
+
+ return;
}
- return;
}
}
}
/* use the last one */
- if (!_events.empty() && (channel_mask & (1 << (*_events.rbegin())->note()->channel ()))) {
- unique_select (*(_events.rbegin()));
+ if (!_events.empty() && last_note) {
+ unique_select (last_note);
}
}
{
bool had_selected = false;
- time_sort_events ();
+ /* we previously time sorted events here, but Notes is a multiset sorted by time */
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if ((*i)->selected()) {
- selected.insert ((*i)->note());
+ if (i->second->selected()) {
+ selected.insert (i->first);
had_selected = true;
}
}
if (allow_all_if_none_selected && !had_selected) {
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- selected.insert ((*i)->note());
+ selected.insert (i->first);
}
}
}
PublicEditor& editor = trackview.editor ();
- framepos_t const unsnapped_frame = editor.pixel_to_sample (x);
+ samplepos_t const unsnapped_sample = editor.pixel_to_sample (x);
const int32_t divisions = editor.get_grid_music_divisions (state);
const bool shift_snap = midi_view()->note_mode() != Percussive;
- const Evoral::Beats snapped_beats = snap_frame_to_grid_underneath (unsnapped_frame, divisions, shift_snap);
+ const Temporal::Beats snapped_beats = snap_sample_to_grid_underneath (unsnapped_sample, divisions, shift_snap);
/* prevent Percussive mode from displaying a ghost hit at region end */
if (!shift_snap && snapped_beats >= midi_region()->start_beats() + midi_region()->length_beats()) {
}
/* calculate time in beats relative to start of source */
- const Evoral::Beats length = get_grid_beats(unsnapped_frame + _region->position());
+ const Temporal::Beats length = get_grid_beats(unsnapped_sample + _region->position());
_ghost_note->note()->set_time (snapped_beats);
_ghost_note->note()->set_length (length);
uint16_t chn_mask = mtv->midi_track()->get_playback_channel_mask();
if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
- get_events (e, Evoral::Sequence<Evoral::Beats>::PitchGreaterThanOrEqual, (uint8_t) floor (note), chn_mask);
+ get_events (e, Evoral::Sequence<Temporal::Beats>::PitchGreaterThanOrEqual, (uint8_t) floor (note), chn_mask);
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
- get_events (e, Evoral::Sequence<Evoral::Beats>::PitchLessThanOrEqual, (uint8_t) floor (note), chn_mask);
+ get_events (e, Evoral::Sequence<Temporal::Beats>::PitchLessThanOrEqual, (uint8_t) floor (note), chn_mask);
} else {
return;
}
}
for (Events::iterator i = e.begin(); i != e.end(); ++i) {
- if (_selection.insert (*i).second) {
- (*i)->set_selected (true);
+ if (_selection.insert (i->second).second) {
+ i->second->set_selected (true);
}
}
_patch_change_fill = UIConfiguration::instance().color_mod ("midi patch change fill", "midi patch change fill");
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- (*i)->set_selected ((*i)->selected()); // will change color
+ i->second->set_selected (i->second->selected()); // will change color
}
/* XXX probably more to do here */
}
void
-MidiRegionView::show_step_edit_cursor (Evoral::Beats pos)
+MidiRegionView::show_step_edit_cursor (Temporal::Beats pos)
{
if (_step_edit_cursor == 0) {
ArdourCanvas::Item* const group = get_canvas_group();
}
void
-MidiRegionView::move_step_edit_cursor (Evoral::Beats pos)
+MidiRegionView::move_step_edit_cursor (Temporal::Beats pos)
{
_step_edit_cursor_position = pos;
if (_step_edit_cursor) {
- double pixel = trackview.editor().sample_to_pixel (region_beats_to_region_frames (pos));
+ double pixel = trackview.editor().sample_to_pixel (region_beats_to_region_samples (pos));
_step_edit_cursor->set_x0 (pixel);
set_step_edit_cursor_width (_step_edit_cursor_width);
}
}
void
-MidiRegionView::set_step_edit_cursor_width (Evoral::Beats beats)
+MidiRegionView::set_step_edit_cursor_width (Temporal::Beats beats)
{
_step_edit_cursor_width = beats;
if (_step_edit_cursor) {
_step_edit_cursor->set_x1 (_step_edit_cursor->x0() + trackview.editor().sample_to_pixel (
- region_beats_to_region_frames (_step_edit_cursor_position + beats)
- - region_beats_to_region_frames (_step_edit_cursor_position)));
+ region_beats_to_region_samples (_step_edit_cursor_position + beats)
+ - region_beats_to_region_samples (_step_edit_cursor_position)));
}
}
boost::shared_ptr<MidiBuffer> buf = mtv->midi_track()->get_gui_feed_buffer ();
- framepos_t back = max_framepos;
+ samplepos_t back = max_samplepos;
for (MidiBuffer::iterator i = buf->begin(); i != buf->end(); ++i) {
const Evoral::Event<MidiBuffer::TimeType>& ev = *i;
}
}
- /* convert from session frames to source beats */
- Evoral::Beats const time_beats = _source_relative_time_converter.from(
+ /* convert from session samples to source beats */
+ Temporal::Beats const time_beats = _source_relative_time_converter.from(
ev.time() - src->timeline_position() + _region->start());
if (ev.type() == MIDI_CMD_NOTE_ON) {
boost::shared_ptr<NoteType> note (
- new NoteType (ev.channel(), time_beats, Evoral::Beats(), ev.note(), ev.velocity()));
+ new NoteType (ev.channel(), time_beats, Temporal::Beats(), ev.note(), ev.velocity()));
add_note (note, true);
return (*n)->velocity() + (frac * ((*m)->velocity() - (*n)->velocity()));
}
-/** @param p A session framepos.
+/** @param p A session samplepos.
* @param divisions beat division to snap given by Editor::get_grid_music_divisions() where
* bar is -1, 0 is audio samples and a positive integer is beat subdivisions.
* @return beat duration of p snapped to the grid subdivision underneath it.
*/
-Evoral::Beats
-MidiRegionView::snap_frame_to_grid_underneath (framepos_t p, int32_t divisions, bool shift_snap) const
+Temporal::Beats
+MidiRegionView::snap_sample_to_grid_underneath (samplepos_t p, int32_t divisions, bool shift_snap) const
{
TempoMap& map (trackview.session()->tempo_map());
- double eqaf = map.exact_qn_at_frame (p + _region->position(), divisions);
+ double eqaf = map.exact_qn_at_sample (p + _region->position(), divisions);
if (divisions != 0 && shift_snap) {
- const double qaf = map.quarter_note_at_frame (p + _region->position());
+ const double qaf = map.quarter_note_at_sample (p + _region->position());
/* Hack so that we always snap to the note that we are over, instead of snapping
to the next one if we're more than halfway through the one we're over.
*/
- const Evoral::Beats grid_beats = get_grid_beats (p + _region->position());
+ const Temporal::Beats grid_beats = get_grid_beats (p + _region->position());
const double rem = eqaf - qaf;
if (rem >= 0.0) {
eqaf -= grid_beats.to_double();
}
const double session_start_off = _region->quarter_note() - midi_region()->start_beats();
- return Evoral::Beats (eqaf - session_start_off);
+ return Temporal::Beats (eqaf - session_start_off);
}
ChannelMode
}
-Evoral::Beats
-MidiRegionView::get_grid_beats(framepos_t pos) const
+Temporal::Beats
+MidiRegionView::get_grid_beats(samplepos_t pos) const
{
PublicEditor& editor = trackview.editor();
bool success = false;
- Evoral::Beats beats = editor.get_grid_type_as_beats (success, pos);
+ Temporal::Beats beats = editor.get_grid_type_as_beats (success, pos);
if (!success) {
- beats = Evoral::Beats(1);
+ beats = Temporal::Beats(1);
}
return beats;
}
{
return contents_height() - (note + 1 - _current_range_min) * note_height() + 1;
}
+
+double
+MidiRegionView::session_relative_qn (double qn) const
+{
+ return qn + (region()->quarter_note() - midi_region()->start_beats());
+}