replace ::cast_dynamic() with relevant ActionManager::get_*_action() calls
[ardour.git] / gtk2_ardour / midi_region_view.h
index 9c85401593c7c121a99275341cc71fd10eeb1b3d..c13bd2d0abd859efc4b9786301d3e962e6c9c0ab 100644 (file)
@@ -65,8 +65,8 @@ class CursorContext;
 class MidiRegionView : public RegionView
 {
 public:
-       typedef Evoral::Note<Evoral::Beats> NoteType;
-       typedef Evoral::Sequence<Evoral::Beats>::Notes Notes;
+       typedef Evoral::Note<Temporal::Beats> NoteType;
+       typedef Evoral::Sequence<Temporal::Beats>::Notes Notes;
 
        MidiRegionView (ArdourCanvas::Container*              parent,
                        RouteTimeAxisView&                    tv,
@@ -99,8 +99,8 @@ public:
        { return midi_view()->midi_view(); }
 
        void step_add_note (uint8_t channel, uint8_t number, uint8_t velocity,
-                           Evoral::Beats pos, Evoral::Beats len);
-       void step_sustain (Evoral::Beats beats);
+                           Temporal::Beats pos, Temporal::Beats len);
+       void step_sustain (Temporal::Beats beats);
        void set_height (double);
        void apply_note_range(uint8_t lowest, uint8_t highest, bool force=false);
 
@@ -109,23 +109,24 @@ public:
        uint32_t get_fill_color() const;
        void color_handler ();
 
-       void show_step_edit_cursor (Evoral::Beats pos);
-       void move_step_edit_cursor (Evoral::Beats pos);
+       void show_step_edit_cursor (Temporal::Beats pos);
+       void move_step_edit_cursor (Temporal::Beats pos);
        void hide_step_edit_cursor ();
-       void set_step_edit_cursor_width (Evoral::Beats beats);
+       void set_step_edit_cursor_width (Temporal::Beats beats);
 
        void redisplay_model();
 
        GhostRegion* add_ghost (TimeAxisView&);
 
        NoteBase* add_note(const boost::shared_ptr<NoteType> note, bool visible);
-       void resolve_note(uint8_t note_num, Evoral::Beats end_time);
+       void resolve_note(uint8_t note_num, Temporal::Beats end_time);
 
        void cut_copy_clear (Editing::CutCopyOp);
-       bool paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx, const int32_t sub_num);
-       void paste_internal (framepos_t pos, unsigned paste_count, float times, const MidiCutBuffer&);
+       bool paste (samplepos_t pos, const ::Selection& selection, PasteContext& ctx, const int32_t sub_num);
+       void paste_internal (samplepos_t pos, unsigned paste_count, float times, const MidiCutBuffer&);
 
        void add_canvas_patch_change (ARDOUR::MidiModel::PatchChangePtr patch, const std::string& displaytext, bool);
+       void remove_canvas_patch_change (PatchChange* pc);
 
        /** Look up the given time and channel in the 'automation' and set keys accordingly.
         * @param time the time of the patch change event
@@ -133,7 +134,7 @@ public:
         * @key a reference to an instance of MIDI::Name::PatchPrimaryKey whose fields will
         *        will be set according to the result of the lookup
         */
-       void get_patch_key_at (Evoral::Beats time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const;
+       void get_patch_key_at (Temporal::Beats time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const;
 
        /** Convert a given PatchChange into a PatchPrimaryKey
         */
@@ -144,10 +145,10 @@ public:
         * @param new_patch new patch
         */
        void change_patch_change (PatchChange& old_patch, const MIDI::Name::PatchPrimaryKey& new_patch);
-       void change_patch_change (ARDOUR::MidiModel::PatchChangePtr, Evoral::PatchChange<Evoral::Beats> const &);
+       void change_patch_change (ARDOUR::MidiModel::PatchChangePtr, Evoral::PatchChange<Temporal::Beats> const &);
 
-       void add_patch_change (framecnt_t, Evoral::PatchChange<Evoral::Beats> const &);
-       void move_patch_change (PatchChange &, Evoral::Beats);
+       void add_patch_change (samplecnt_t, Evoral::PatchChange<Temporal::Beats> const &);
+       void move_patch_change (PatchChange &, Temporal::Beats);
        void delete_patch_change (PatchChange *);
        void edit_patch_change (PatchChange *);
 
@@ -175,11 +176,11 @@ public:
 
        void start_note_diff_command (std::string name = "midi edit");
        void note_diff_add_change (NoteBase* ev, ARDOUR::MidiModel::NoteDiffCommand::Property, uint8_t val);
-       void note_diff_add_change (NoteBase* ev, ARDOUR::MidiModel::NoteDiffCommand::Property, Evoral::Beats val);
+       void note_diff_add_change (NoteBase* ev, ARDOUR::MidiModel::NoteDiffCommand::Property, Temporal::Beats val);
        void note_diff_add_note (const boost::shared_ptr<NoteType> note, bool selected, bool show_velocity = false);
        void note_diff_remove_note (NoteBase* ev);
 
-       void apply_diff (bool as_subcommand = false);
+       void apply_diff (bool as_subcommand = false, bool was_copy = false);
        void abort_command();
 
        void   note_entered(NoteBase* ev);
@@ -196,11 +197,14 @@ public:
        void   delete_note (boost::shared_ptr<NoteType>);
        size_t selection_size() { return _selection.size(); }
        void   select_all_notes ();
-       void   select_range(framepos_t start, framepos_t end);
+       void   select_range(samplepos_t start, samplepos_t end);
        void   invert_selection ();
 
+       Temporal::Beats earliest_in_selection ();
        void move_selection(double dx, double dy, double cumulative_dy);
-       void note_dropped (NoteBase* ev, ARDOUR::frameoffset_t, int8_t d_note);
+       void note_dropped (NoteBase* ev, double d_qn, int8_t d_note, bool copy);
+       NoteBase* copy_selection (NoteBase* primary);
+       void move_copies(double dx_qn, double dy, double cumulative_dy);
 
        void select_notes (std::list<Evoral::event_id_t>);
        void select_matching_notes (uint8_t notenum, uint16_t channel_mask, bool add, bool extend);
@@ -255,49 +259,51 @@ public:
         */
        double snap_to_pixel(double x, bool ensure_snap = false);
 
-       /** Snap a region relative pixel coordinate to frame units.
+       /** Snap a region relative pixel coordinate to sample units.
         * @param x a pixel coordinate relative to region start
         * @param ensure_snap ignore SnapOff and magnetic snap.
         * Required for inverting snap logic with modifier keys and snap delta calculation.
-        * @return the snapped framepos_t coordinate relative to region start
+        * @return the snapped samplepos_t coordinate relative to region start
         */
-       framepos_t snap_pixel_to_sample(double x, bool ensure_snap = false);
+       samplepos_t snap_pixel_to_sample(double x, bool ensure_snap = false);
 
-       /** Convert a timestamp in beats into frames (both relative to region position) */
-       framepos_t region_beats_to_region_frames(Evoral::Beats beats) const;
-       /** Convert a timestamp in beats into absolute frames */
-       framepos_t region_beats_to_absolute_frames(Evoral::Beats beats) const {
-               return _region->position() + region_beats_to_region_frames (beats);
+       /** Convert a timestamp in beats into samples (both relative to region position) */
+       samplepos_t region_beats_to_region_samples(Temporal::Beats beats) const;
+       /** Convert a timestamp in beats into absolute samples */
+       samplepos_t region_beats_to_absolute_samples(Temporal::Beats beats) const {
+               return _region->position() + region_beats_to_region_samples (beats);
        }
-       /** Convert a timestamp in frames to beats (both relative to region position) */
-       Evoral::Beats region_frames_to_region_beats(framepos_t) const;
-       double region_frames_to_region_beats_double(framepos_t) const;
-
-       /** Convert a timestamp in beats measured from source start into absolute frames */
-       framepos_t source_beats_to_absolute_frames(Evoral::Beats beats) const;
-       /** Convert a timestamp in beats measured from source start into region-relative frames */
-       framepos_t source_beats_to_region_frames(Evoral::Beats beats) const {
-               return source_beats_to_absolute_frames (beats) - _region->position();
+       /** Convert a timestamp in samples to beats (both relative to region position) */
+       Temporal::Beats region_samples_to_region_beats(samplepos_t) const;
+       double region_samples_to_region_beats_double(samplepos_t) const;
+
+       /** Convert a timestamp in beats measured from source start into absolute samples */
+       samplepos_t source_beats_to_absolute_samples(Temporal::Beats beats) const;
+       /** Convert a timestamp in beats measured from source start into region-relative samples */
+       samplepos_t source_beats_to_region_samples(Temporal::Beats beats) const {
+               return source_beats_to_absolute_samples (beats) - _region->position();
        }
-       /** Convert a timestamp in absolute frames to beats measured from source start*/
-       Evoral::Beats absolute_frames_to_source_beats(framepos_t) const;
+       /** Convert a timestamp in absolute samples to beats measured from source start*/
+       Temporal::Beats absolute_samples_to_source_beats(samplepos_t) const;
 
-       ARDOUR::BeatsFramesConverter const & region_relative_time_converter () const {
+       ARDOUR::BeatsSamplesConverter const & region_relative_time_converter () const {
                return _region_relative_time_converter;
        }
 
-       ARDOUR::BeatsFramesConverter const & source_relative_time_converter () const {
+       ARDOUR::BeatsSamplesConverter const & source_relative_time_converter () const {
                return _source_relative_time_converter;
        }
 
-       ARDOUR::DoubleBeatsFramesConverter const & region_relative_time_converter_double () const {
+       ARDOUR::DoubleBeatsSamplesConverter const & region_relative_time_converter_double () const {
                return _region_relative_time_converter_double;
        }
 
+       double session_relative_qn (double qn) const;
+
        void goto_previous_note (bool add_to_selection);
        void goto_next_note (bool add_to_selection);
-       void change_note_lengths (bool, bool, Evoral::Beats beats, bool start, bool end);
-        void change_velocities (bool up, bool fine, bool allow_smush, bool all_together);
+       void change_note_lengths (bool, bool, Temporal::Beats beats, bool start, bool end);
+       void change_velocities (bool up, bool fine, bool allow_smush, bool all_together);
        void transpose (bool up, bool fine, bool allow_smush);
        void nudge_notes (bool forward, bool fine);
        void channel_edit ();
@@ -321,13 +327,13 @@ public:
        void trim_front_ending ();
 
        /** 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 state the keyboard modifier mask for the canvas event (click).
         * \param shift_snap true alters snap behavior to round down always (false if the gui has already done that).
         */
-       void create_note_at (framepos_t t, double y, Evoral::Beats length, uint32_t state, bool shift_snap);
+       void create_note_at (samplepos_t t, double y, Temporal::Beats length, uint32_t state, bool shift_snap);
 
        /** An external request to clear the note selection, remove MRV from editor
         * selection.
@@ -355,8 +361,10 @@ private:
 
        friend class MidiRubberbandSelectDrag;
        friend class MidiVerticalSelectDrag;
+       friend class NoteDrag;
        friend class NoteCreateDrag;
        friend class HitCreateDrag;
+       friend class MidiGhostRegion;
 
        friend class EditNoteDialog;
 
@@ -379,7 +387,7 @@ private:
        bool note_canvas_event(GdkEvent* ev);
 
        void midi_channel_mode_changed ();
-        PBD::ScopedConnection _channel_mode_changed_connection;
+       PBD::ScopedConnection _channel_mode_changed_connection;
        void instrument_settings_changed ();
        PBD::ScopedConnection _instrument_changed_connection;
 
@@ -391,7 +399,7 @@ private:
        void trim_note(NoteBase* ev, ARDOUR::MidiModel::TimeType start_delta,
                       ARDOUR::MidiModel::TimeType end_delta);
 
-       void update_drag_selection (framepos_t start, framepos_t end, double y0, double y1, bool extend);
+       void update_drag_selection (samplepos_t start, samplepos_t end, double y0, double y1, bool extend);
        void update_vertical_drag_selection (double last_y, double y, bool extend);
 
        void add_to_selection (NoteBase*);
@@ -407,16 +415,18 @@ private:
        uint8_t  _current_range_min;
        uint8_t  _current_range_max;
 
-       typedef std::list<NoteBase*>                          Events;
-       typedef std::vector< boost::shared_ptr<PatchChange> > PatchChanges;
-       typedef std::vector< boost::shared_ptr<SysEx> >       SysExes;
+       typedef boost::unordered_map<boost::shared_ptr<NoteType>, NoteBase*>                             Events;
+       typedef boost::unordered_map<ARDOUR::MidiModel::PatchChangePtr, boost::shared_ptr<PatchChange> > PatchChanges;
+       typedef boost::unordered_map<ARDOUR::MidiModel::constSysExPtr, boost::shared_ptr<SysEx> >        SysExes;
+       typedef std::vector<NoteBase*> CopyDragEvents;
 
-       ARDOUR::BeatsFramesConverter _region_relative_time_converter;
-       ARDOUR::BeatsFramesConverter _source_relative_time_converter;
-       ARDOUR::DoubleBeatsFramesConverter _region_relative_time_converter_double;
+       ARDOUR::BeatsSamplesConverter _region_relative_time_converter;
+       ARDOUR::BeatsSamplesConverter _source_relative_time_converter;
+       ARDOUR::DoubleBeatsSamplesConverter _region_relative_time_converter_double;
 
        boost::shared_ptr<ARDOUR::MidiModel> _model;
        Events                               _events;
+       CopyDragEvents                       _copy_drag_events;
        PatchChanges                         _patch_changes;
        SysExes                              _sys_exes;
        Note**                               _active_notes;
@@ -426,8 +436,8 @@ private:
        double                               _last_ghost_x;
        double                               _last_ghost_y;
        ArdourCanvas::Rectangle*             _step_edit_cursor;
-       Evoral::Beats                        _step_edit_cursor_width;
-       Evoral::Beats                        _step_edit_cursor_position;
+       Temporal::Beats                      _step_edit_cursor_width;
+       Temporal::Beats                      _step_edit_cursor_position;
        NoteBase*                            _channel_selection_scoped_note;
 
        MouseState _mouse_state;
@@ -436,9 +446,6 @@ private:
        /** Currently selected NoteBase objects */
        Selection _selection;
 
-       bool _sort_needed;
-       void time_sort_events ();
-
        MidiCutBuffer* selection_as_cut_buffer () const;
 
        /** New notes (created in the current command) which should be selected
@@ -461,6 +468,9 @@ private:
        NoteBase* find_canvas_note (Evoral::event_id_t id);
        Events::iterator _optimization_iterator;
 
+       boost::shared_ptr<PatchChange> find_canvas_patch_change (ARDOUR::MidiModel::PatchChangePtr p);
+       boost::shared_ptr<SysEx> find_canvas_sys_ex (ARDOUR::MidiModel::SysExPtr s);
+
        void update_note (NoteBase*, bool update_ghost_regions = true);
        void update_sustained (Note *, bool update_ghost_regions = true);
        void update_hit (Hit *, bool update_ghost_regions = true);
@@ -485,7 +495,7 @@ private:
 
        void drop_down_keys ();
        void maybe_select_by_position (GdkEventButton* ev, double x, double y);
-       void get_events (Events& e, Evoral::Sequence<Evoral::Beats>::NoteOperator op, uint8_t val, int chan_mask = 0);
+       void get_events (Events& e, Evoral::Sequence<Temporal::Beats>::NoteOperator op, uint8_t val, int chan_mask = 0);
 
        void display_patch_changes_on_channel (uint8_t, bool);
 
@@ -493,7 +503,7 @@ private:
        void data_recorded (boost::weak_ptr<ARDOUR::MidiSource>);
 
        /** Get grid type as beats, or default to 1 if not snapped to beats. */
-       Evoral::Beats get_grid_beats(framepos_t pos) const;
+       Temporal::Beats get_grid_beats(samplepos_t pos) const;
 
        void remove_ghost_note ();
        void mouse_mode_changed ();
@@ -501,7 +511,7 @@ private:
        void leave_internal ();
        void hide_verbose_cursor ();
 
-       framecnt_t _last_display_zoom;
+       samplecnt_t _last_display_zoom;
 
        double    _last_event_x;
        double    _last_event_y;
@@ -511,14 +521,24 @@ private:
 
        bool _mouse_changed_selection;
 
-       Evoral::Beats snap_frame_to_grid_underneath (framepos_t p, int32_t divisions, bool shift_snap) const;
+       Gtkmm2ext::Color _patch_change_outline;
+       Gtkmm2ext::Color _patch_change_fill;
+
+       Temporal::Beats snap_sample_to_grid_underneath (samplepos_t p, int32_t divisions, bool shift_snap) const;
 
        PBD::ScopedConnection _mouse_mode_connection;
 
        boost::shared_ptr<CursorContext> _press_cursor_ctx;
 
-        ARDOUR::ChannelMode get_channel_mode() const;
-        uint16_t get_selected_channels () const;
+       ARDOUR::ChannelMode get_channel_mode() const;
+       uint16_t get_selected_channels () const;
+
+       inline double contents_height() const { return (_height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 2); }
+       inline double contents_note_range () const { return (double)(_current_range_max - _current_range_min + 1); }
+       inline double note_height() const { return contents_height() / contents_note_range(); }
+
+       double note_to_y (uint8_t note) const;
+       uint8_t y_to_note (double y) const;
 };