Shut up.
[ardour.git] / gtk2_ardour / midi_region_view.h
1 /*
2     Copyright (C) 2001-2007 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifndef __gtk_ardour_midi_region_view_h__
20 #define __gtk_ardour_midi_region_view_h__
21
22 #include <string>
23 #include <vector>
24
25 #include <libgnomecanvasmm.h>
26 #include <libgnomecanvasmm/polygon.h>
27 #include "ardour/midi_track.h"
28 #include "ardour/midi_region.h"
29 #include "ardour/midi_model.h"
30 #include "ardour/diskstream.h"
31 #include "ardour/types.h"
32
33 #include "region_view.h"
34 #include "midi_time_axis.h"
35 #include "time_axis_view_item.h"
36 #include "automation_line.h"
37 #include "enums.h"
38 #include "canvas.h"
39 #include "canvas-note.h"
40 #include "canvas-note-event.h"
41 #include "canvas-program-change.h"
42 #include "canvas-sysex.h"
43
44 namespace ARDOUR {
45         class MidiRegion;
46         class MidiModel;
47 };
48
49 namespace MIDI {
50         namespace Name {
51                 struct PatchPrimaryKey;
52         };
53 };
54
55 class MidiTimeAxisView;
56 class GhostRegion;
57 class AutomationTimeAxisView;
58 class AutomationRegionView;
59
60 class MidiRegionView : public RegionView
61 {
62   public:
63         typedef Evoral::Note<ARDOUR::MidiModel::TimeType> NoteType;
64
65         MidiRegionView (ArdourCanvas::Group *,
66                         RouteTimeAxisView&,
67                         boost::shared_ptr<ARDOUR::MidiRegion>,
68                         double initial_samples_per_unit,
69                         Gdk::Color& basic_color);
70         
71         MidiRegionView (const MidiRegionView& other);
72         MidiRegionView (const MidiRegionView& other, boost::shared_ptr<ARDOUR::MidiRegion>);
73
74         ~MidiRegionView ();
75
76         virtual void init (Gdk::Color& basic_color, bool wfd);
77
78         inline const boost::shared_ptr<ARDOUR::MidiRegion> midi_region() const
79                 { return boost::dynamic_pointer_cast<ARDOUR::MidiRegion>(_region); }
80
81         inline MidiTimeAxisView* midi_view() const
82                 { return dynamic_cast<MidiTimeAxisView*>(&trackview); }
83
84         inline MidiStreamView* midi_stream_view() const
85                 { return midi_view()->midi_view(); }
86
87         void set_height (double);
88         void apply_note_range(uint8_t lowest, uint8_t highest, bool force=false);
89
90         inline ARDOUR::ColorMode color_mode() const { return midi_view()->color_mode(); }
91         
92         void set_frame_color();
93
94         void redisplay_model();
95
96         GhostRegion* add_ghost (TimeAxisView&);
97
98         void add_note(const boost::shared_ptr<NoteType> note);
99         void resolve_note(uint8_t note_num, double end_time);
100         
101         struct PCEvent {
102                 PCEvent(double a_time, uint8_t a_value, uint8_t a_channel) 
103                         : time(a_time), value(a_value), channel(a_channel) {}
104
105                 double  time;
106                 uint8_t value;
107                 uint8_t channel;
108         };
109         
110         /** Add a new program change flag to the canvas.
111          * @param program the MidiRegionView::PCEvent to add
112          * @param the text to display in the flag
113          */
114         void add_pgm_change(PCEvent& program, const std::string& displaytext);
115         
116         /** Look up the given time and channel in the 'automation' and set keys accordingly.
117          * @param time the time of the program change event
118          * @param channel the MIDI channel of the event
119          * @key a reference to an instance of MIDI::Name::PatchPrimaryKey whose fields will 
120          *        will be set according to the result of the lookup
121          */
122         void get_patch_key_at(double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key);
123         
124         /** Change the 'automation' data of old_program to new values which correspond to new_patch.
125          * @param old_program the program change event which is to be altered
126          * @param new_patch the new lsb, msb and program number which are to be set
127          */
128         void alter_program_change(PCEvent& old_program, const MIDI::Name::PatchPrimaryKey& new_patch);
129         
130         /** Alter a given program to the new given one.
131          * (Called on context menu select on CanvasProgramChange)
132          */
133         void program_selected(
134                 ArdourCanvas::CanvasProgramChange& program, 
135                 const MIDI::Name::PatchPrimaryKey& new_patch);
136         
137         /** Alter a given program to be its predecessor in the MIDNAM file.
138          */
139         void previous_program(ArdourCanvas::CanvasProgramChange& program);
140
141         /** Alters a given program to be its successor in the MIDNAM file.
142          */
143         void next_program(ArdourCanvas::CanvasProgramChange& program);
144         
145         /** Displays all program change events in the region as flags on the canvas.
146          */
147         void display_program_changes();
148         
149         /** Displays all system exclusive events in the region as flags on the canvas.
150          */
151         void display_sysexes();
152
153         void begin_write();
154         void end_write();
155         void extend_active_notes();
156
157         void create_note_at(double x, double y, double length);
158
159         void display_model(boost::shared_ptr<ARDOUR::MidiModel> model);
160
161         void start_delta_command(std::string name = "midi edit");
162         void command_add_note(const boost::shared_ptr<NoteType> note, bool selected);
163         void command_remove_note(ArdourCanvas::CanvasNoteEvent* ev);
164
165         void apply_command();
166         void abort_command();
167
168         void   note_entered(ArdourCanvas::CanvasNoteEvent* ev);
169         void   unique_select(ArdourCanvas::CanvasNoteEvent* ev);
170         void   note_selected(ArdourCanvas::CanvasNoteEvent* ev, bool add);
171         void   note_deselected(ArdourCanvas::CanvasNoteEvent* ev, bool add);
172         void   delete_selection();
173         size_t selection_size() { return _selection.size(); }
174
175         void move_selection(double dx, double dy);
176         void note_dropped(ArdourCanvas::CanvasNoteEvent* ev, double d_frames, uint8_t d_note);
177
178         /** Return true iff the note is within the currently visible range */
179         bool note_in_visible_range(const boost::shared_ptr<NoteType> note) const;
180
181         /** Get the region position in pixels relative to session. */
182         double get_position_pixels();
183
184         /** Begin resizing of some notes.
185          * Called by CanvasMidiNote when resizing starts.
186          * @param note_end which end of the note, NOTE_ON or NOTE_OFF
187          */
188         void begin_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end);
189
190         /** Update resizing notes while user drags.
191          * @param note_end which end of the note, NOTE_ON or NOTE_OFF
192          * @param x the difference in mouse motion, ie the motion difference if relative=true
193          *           or the absolute mouse position (track-relative) if relative is false
194          * @param relative true if relative resizing is taking place, false if absolute resizing
195          */
196         void update_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end, double x, bool relative);
197
198         /** Finish resizing notes when the user releases the mouse button.
199          * @param note_end which end of the note, NOTE_ON or NOTE_OFF
200          * @param event_x the absolute mouse position (track-relative)
201          * @param relative true if relative resizing is taking place, false if absolute resizing
202          */
203         void commit_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end, double event_x, bool relative);
204
205         /** Adjust the velocity on a note, and the selection if applicable.
206          * @param velocity the relative or absolute velocity
207          * @param relative whether velocity is relative or absolute
208          */
209         void change_velocity(ArdourCanvas::CanvasNoteEvent* ev, int8_t velocity, bool relative=false);
210         
211         /** Change the channel of the selection.
212          * @param channel - the channel number of the new channel, zero-based
213          */
214         void change_channel(uint8_t channel);
215
216         enum MouseState {
217                 None,
218                 Pressed,
219                 SelectTouchDragging,
220                 SelectRectDragging,
221                 AddDragging,
222                 EraseTouchDragging
223         };
224
225         MouseState mouse_state() const { return _mouse_state; }
226
227         struct NoteResizeData {
228                 ArdourCanvas::CanvasNote  *canvas_note;
229                 ArdourCanvas::SimpleRect  *resize_rect;
230                 double                     current_x;
231         };
232         
233         /** Snap a region relative pixel coordinate to pixel units.
234          * for pixel units (double) instead of nframes64_t
235          * @param x a pixel coordinate relative to region start
236          * @return the snapped pixel coordinate relative to region start
237          */
238         double snap_to_pixel(double x);
239
240         /** Snap a region relative pixel coordinate to frame units.
241          * @param x a pixel coordinate relative to region start
242          * @return the snapped nframes64_t coordinate relative to region start
243          */
244         nframes64_t snap_to_frame(double x);
245
246         /** Snap a region relative frame coordinate to frame units.
247          * @param x a pixel coordinate relative to region start
248          * @return the snapped nframes64_t coordinate relative to region start
249          */
250         nframes64_t snap_to_frame(nframes64_t x);
251         
252         /** Convert a timestamp in beats to frames (both relative to region start) */
253         nframes64_t beats_to_frames(double beats) const;
254         
255         /** Convert a timestamp in frames to beats (both relative to region start) */
256         double frames_to_beats(nframes64_t beats) const;
257         
258   protected:
259     /** Allows derived types to specify their visibility requirements
260      * to the TimeAxisViewItem parent class.
261      */
262     MidiRegionView (ArdourCanvas::Group *,
263                         RouteTimeAxisView&,
264                         boost::shared_ptr<ARDOUR::MidiRegion>,
265                         double samples_per_unit,
266                         Gdk::Color& basic_color,
267                         TimeAxisViewItem::Visibility);
268
269     void region_resized (ARDOUR::Change);
270
271     void set_flags (XMLNode *);
272     void store_flags ();
273
274         void reset_width_dependent_items (double pixel_width);
275
276   private:
277         /** Play the NoteOn event of the given note immediately
278          * and schedule the playback of the corresponding NoteOff event.
279          */
280         void play_midi_note(boost::shared_ptr<NoteType> note);
281         
282         /** Play the NoteOff-Event of the given note immediately
283          * (scheduled by @ref play_midi_note()).
284          */
285         bool play_midi_note_off(boost::shared_ptr<NoteType> note);
286
287         void clear_events();
288         void switch_source(boost::shared_ptr<ARDOUR::Source> src);
289
290         bool canvas_event(GdkEvent* ev);
291         bool note_canvas_event(GdkEvent* ev);
292         
293         void midi_channel_mode_changed(ARDOUR::ChannelMode mode, uint16_t mask);
294         void midi_patch_settings_changed(std::string model, std::string custom_device_mode);
295         
296         void change_note_velocity(ArdourCanvas::CanvasNoteEvent* ev, int8_t vel, bool relative=false);
297
298         void clear_selection_except(ArdourCanvas::CanvasNoteEvent* ev);
299         void clear_selection() { clear_selection_except(NULL); }
300         void update_drag_selection(double last_x, double x, double last_y, double y);
301
302         int8_t   _force_channel;
303         uint16_t _last_channel_selection;
304         double   _default_note_length;
305         uint8_t  _current_range_min;
306         uint8_t  _current_range_max;
307         
308         /// MIDNAM information of the current track: Model name of MIDNAM file
309         std::string _model_name;
310         
311         /// MIDNAM information of the current track: CustomDeviceMode
312         std::string _custom_device_mode;   
313
314         typedef std::vector<ArdourCanvas::CanvasNoteEvent*> Events;
315         typedef std::vector< boost::shared_ptr<ArdourCanvas::CanvasProgramChange> > PgmChanges;
316         typedef std::vector< boost::shared_ptr<ArdourCanvas::CanvasSysEx> > SysExes;
317         
318         boost::shared_ptr<ARDOUR::MidiModel> _model;
319         Events                               _events;
320         PgmChanges                           _pgm_changes;
321         SysExes                              _sys_exes;
322         ArdourCanvas::CanvasNote**           _active_notes;
323         ArdourCanvas::Group*                 _note_group;
324         ARDOUR::MidiModel::DeltaCommand*     _delta_command;
325
326         MouseState _mouse_state;
327         int _pressed_button;
328
329         typedef std::set<ArdourCanvas::CanvasNoteEvent*> Selection;
330         /// Currently selected CanvasNoteEvents
331         Selection _selection;
332
333         /** New notes (created in the current command) which should be selected
334          * when they appear after the command is applied. */
335         std::set< boost::shared_ptr<NoteType> > _marked_for_selection;
336
337         std::vector<NoteResizeData *> _resize_data;
338 };
339
340 #endif /* __gtk_ardour_midi_region_view_h__ */