ardour
step_editor.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 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 
20 #include "ardour/midi_track.h"
21 #include "ardour/midi_region.h"
22 #include "ardour/tempo.h"
23 #include "ardour/types.h"
24 
25 #include "gui_thread.h"
26 #include "midi_region_view.h"
27 #include "public_editor.h"
28 #include "step_editor.h"
29 #include "step_entry.h"
30 
31 using namespace ARDOUR;
32 using namespace Gtk;
33 using namespace std;
34 
36  : _editor (e)
37  , _track (t)
38  , step_editor (0)
39  , _mtv (mtv)
40 {
46 
47  _track->PlaylistChanged.connect (*this, invalidator (*this),
48  boost::bind (&StepEditor::playlist_changed, this),
49  gui_context());
51 }
52 
54 {
55  delete step_editor;
56 }
57 
58 void
60 {
66  last_added_pitch = -1;
68 
72 
73  assert (step_edit_region);
74  assert (step_edit_region_view);
75 
76  if (step_editor == 0) {
77  step_editor = new StepEntry (*this);
78  step_editor->signal_delete_event().connect (sigc::mem_fun (*this, &StepEditor::step_editor_hidden));
79  step_editor->signal_hide().connect (sigc::mem_fun (*this, &StepEditor::step_editor_hide));
80  }
81 
84 
85  step_editor->present ();
86 }
87 
88 void
90 {
92 }
93 
94 void
96 {
98  if (step_edit_region) {
100  }
101 }
102 
103 void
105 {
107 
108  if (r) {
110  }
111 
112  if (step_edit_region) {
114  step_edit_region_view = dynamic_cast<MidiRegionView*> (rv);
115 
116  } else {
117 
120 
122 
124  step_edit_region_view = dynamic_cast<MidiRegionView*>(rv);
125  }
126 }
127 
128 
129 void
131 {
132  assert (step_edit_region);
133  assert (step_edit_region_view);
134 
136 
137  if (frames_from_start < 0) {
138  /* this can happen with snap enabled, and the edit point == Playhead. we snap the
139  position of the new region, and it can end up after the edit point.
140  */
141  frames_from_start = 0;
142  }
143 
146 }
147 
148 bool
150 {
151  step_editor_hide ();
152  return true; // XXX remember position ?!
153 }
154 
155 void
157 {
158  /* everything else will follow the change in the model */
159  _track->set_step_editing (false);
160 }
161 
162 void
164 {
165  if (step_editor) {
166  step_editor->hide ();
167  }
168 
169  if (step_edit_region_view) {
171  }
172 
174 }
175 
176 void
178 {
180  uint8_t* buf;
181  uint32_t bufsize = 32;
182 
183  buf = new uint8_t[bufsize];
184 
185  while (incoming.read_space()) {
186  framepos_t time;
187  Evoral::EventType type;
188  uint32_t size;
189 
190  incoming.read_prefix (&time, &type, &size);
191 
192  if (size > bufsize) {
193  delete [] buf;
194  bufsize = size;
195  buf = new uint8_t[bufsize];
196  }
197 
198  incoming.read_contents (size, buf);
199 
200  if ((buf[0] & 0xf0) == MIDI_CMD_NOTE_ON) {
201  step_add_note (buf[0] & 0xf, buf[1], buf[2], Evoral::Beats());
202  }
203  }
204 }
205 
206 int
207 StepEditor::step_add_bank_change (uint8_t /*channel*/, uint8_t /*bank*/)
208 {
209  return 0;
210 }
211 
212 int
213 StepEditor::step_add_program_change (uint8_t /*channel*/, uint8_t /*program*/)
214 {
215  return 0;
216 }
217 
218 void
220 {
221  if (step_edit_region_view) {
223  }
224 }
225 
226 void
228 {
229  if (beats > 0.0) {
230  step_edit_beat_pos = min (step_edit_beat_pos + beats,
232  } else if (beats < 0.0) {
233  if (-beats < step_edit_beat_pos) {
234  step_edit_beat_pos += beats; // its negative, remember
235  } else {
237  }
238  }
240 }
241 
242 int
243 StepEditor::step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity, Evoral::Beats beat_duration)
244 {
245  /* do these things in case undo removed the step edit region
246  */
247  if (!step_edit_region) {
253  }
254 
255  assert (step_edit_region);
256  assert (step_edit_region_view);
257 
258  if (beat_duration == 0.0 && step_editor) {
259  beat_duration = step_editor->note_length();
260  } else if (beat_duration == 0.0) {
261  bool success;
262  beat_duration = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
263 
264  if (!success) {
265  return -1;
266  }
267  }
268 
269  MidiStreamView* msv = _mtv.midi_view();
270 
271  /* make sure its visible on the vertical axis */
272 
273  if (pitch < msv->lowest_note() || pitch > msv->highest_note()) {
274  msv->update_note_range (pitch);
276  }
277 
278  /* make sure its visible on the horizontal axis */
279 
281 
282  if (fpos >= (_editor.leftmost_sample() + _editor.current_page_samples())) {
284  }
285 
287  Evoral::Beats len = beat_duration;
288 
289  if ((last_added_pitch >= 0) && (pitch == last_added_pitch) && (last_added_end == step_edit_beat_pos)) {
290 
291  /* avoid any apparent note overlap - move the start of this note
292  up by 1 tick from where the last note ended
293  */
294 
295  at += Evoral::Beats::ticks(1);
296  len -= Evoral::Beats::ticks(1);
297  }
298 
299  step_edit_region_view->step_add_note (channel, pitch, velocity, at, len);
300 
301  last_added_pitch = pitch;
302  last_added_end = at+len;
303 
306 
307  if (_step_edit_triplet_countdown == 0) {
309  }
310  }
311 
313  step_edit_beat_pos += beat_duration;
315  } else {
316  step_edit_beat_pos += Evoral::Beats::ticks(1); // tiny, but no longer overlapping
318  }
319 
320  return 0;
321 }
322 
323 void
325 {
326  if (step_edit_region_view) {
328  }
329 }
330 
331 bool
333 {
334  return _step_edit_triplet_countdown > 0;
335 }
336 
337 bool
339 {
341 }
342 
343 void
345 {
346  if (_step_edit_triplet_countdown == 0) {
347  _step_edit_within_chord = false;
349  } else {
351  }
352 }
353 
354 void
356 {
358  _step_edit_within_chord = false;
361  } else {
364  }
365 }
366 
367 void
369 {
370  bool success;
371 
372  if (beats == 0.0) {
374  } else {
375  success = true;
376  }
377 
378  if (success) {
379  step_edit_beat_pos += beats;
381  }
382 }
383 
384 void
386 {
389 }
390 
391 void
393 {
394  Session* _session = _mtv.session ();
395 
396  if (!_session || !step_edit_region_view || !step_edit_region) {
397  return;
398  }
399 
401  fpos = _session->tempo_map().round_to_bar (fpos, RoundUpAlways);
404 }
405 
406 void
408 {
411  boost::bind (&StepEditor::region_removed, this, _1),
412  gui_context());
413 }
414 
415 void
417 {
418  boost::shared_ptr<Region> r (wr.lock());
419 
420  if (!r) {
421  return;
422  }
423 
424  if (step_edit_region == r) {
427  // force a recompute of the insert position
429  }
430 }
431 
432 string
434 {
435  return _track->name();
436 }
RegionView * find_view(boost::shared_ptr< const ARDOUR::Region >)
Definition: streamview.cc:481
void step_edit_bar_sync()
Definition: step_editor.cc:392
Evoral::Beats note_length()
Definition: step_entry.cc:533
void stop_step_editing()
Definition: step_editor.cc:163
#define MIDI_CMD_NOTE_ON
Definition: midi_events.h:108
bool read_contents(uint32_t size, uint8_t *buf)
PBD::ScopedConnection step_edit_region_connection
Definition: step_editor.h:77
boost::shared_ptr< ARDOUR::MidiTrack > _track
Definition: step_editor.h:79
bool step_edit_within_triplet() const
Definition: step_editor.cc:332
Definition: ardour_ui.h:130
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
bool _step_edit_within_chord
Definition: step_editor.h:75
void move_step_edit_beat_pos(Evoral::Beats beats)
Definition: step_editor.cc:227
TempoMap & tempo_map()
Definition: session.h:596
Evoral::Beats _step_edit_chord_duration
Definition: step_editor.h:76
Evoral::Beats last_added_end
Definition: step_editor.h:83
Always round up, even if on a division.
Definition: types.h:225
Evoral::Beats step_edit_beat_pos
Definition: step_editor.h:71
Representation of the interface of the Editor class.
int step_add_program_change(uint8_t channel, uint8_t program)
Definition: step_editor.cc:213
Definition: Beats.hpp:239
void reset_step_edit_beat_pos()
Definition: step_editor.cc:130
void step_sustain(Evoral::Beats beats)
Evoral::Beats region_frames_to_region_beats(framepos_t) const
framecnt_t frame_rate() const
Definition: session.h:365
void playlist_changed()
Definition: step_editor.cc:407
virtual Evoral::Beats get_grid_type_as_beats(bool &success, framepos_t position)=0
#define invalidator(x)
Definition: gui_thread.h:40
framepos_t round_to_bar(framepos_t frame, RoundMode dir)
Definition: tempo.cc:1295
int step_add_note(uint8_t channel, uint8_t pitch, uint8_t velocity, Evoral::Beats beat_duration)
Definition: step_editor.cc:243
std::string name() const
Definition: step_editor.cc:433
const Meter & meter_at(framepos_t) const
Definition: tempo.cc:1652
bool step_edit_within_chord() const
Definition: step_editor.cc:338
boost::shared_ptr< ARDOUR::MidiRegion > add_region(ARDOUR::framepos_t, ARDOUR::framecnt_t, bool)
MidiTimeAxisView & _mtv
Definition: step_editor.h:81
int64_t framecnt_t
Definition: types.h:76
virtual ~StepEditor()
Definition: step_editor.cc:53
int step_add_bank_change(uint8_t channel, uint8_t bank)
Definition: step_editor.cc:207
void show_step_edit_cursor(Evoral::Beats pos)
boost::shared_ptr< Region > top_region_at(framepos_t frame)
Definition: playlist.cc:1727
void step_editor_hide()
Definition: step_editor.cc:156
void step_edit_sustain(Evoral::Beats beats)
Definition: step_editor.cc:219
void step_edit_toggle_chord()
Definition: step_editor.cc:355
PBD::Signal1< void, boost::weak_ptr< Region > > RegionRemoved
Definition: playlist.h:192
Definition: amp.h:29
static Beats ticks(uint32_t ticks)
Definition: Beats.hpp:49
ARDOUR::Session * session() const
Definition: axis_view.h:52
void resync_step_edit_position()
Definition: step_editor.cc:89
#define gui_context()
Definition: gui_thread.h:36
Beats round_up_to_beat() const
Definition: Beats.hpp:67
boost::shared_ptr< Playlist > playlist()
Definition: track.cc:590
void update_note_range(uint8_t note_num)
ARDOUR::framepos_t step_edit_insert_position
Definition: step_editor.h:70
int64_t framepos_t
Definition: types.h:66
void step_edit_toggle_triplet()
Definition: step_editor.cc:344
bool read_prefix(T *time, Evoral::EventType *type, uint32_t *size)
virtual framecnt_t current_page_samples() const =0
void move_step_edit_cursor(Evoral::Beats pos)
void prepare_step_edit_region()
Definition: step_editor.cc:104
void step_edit_beat_sync()
Definition: step_editor.cc:385
framepos_t region_beats_to_absolute_frames(Evoral::Beats beats) const
void set_step_editing(bool yn)
Definition: midi_track.cc:757
uint32_t EventType
Definition: types.hpp:43
PBD::Signal0< void > PlaylistChanged
Definition: track.h:166
framepos_t position() const
Definition: region.h:112
void set_step_edit_cursor_width(Evoral::Beats beats)
uint8_t _step_edit_triplet_countdown
Definition: step_editor.h:74
MidiRegionView * step_edit_region_view
Definition: step_editor.h:73
void step_add_note(uint8_t channel, uint8_t number, uint8_t velocity, Evoral::Beats pos, Evoral::Beats len)
StepEntry * step_editor
Definition: step_editor.h:80
PublicEditor & _editor
Definition: step_editor.h:78
void resync_step_edit_to_edit_point()
Definition: step_editor.cc:95
std::string name() const
virtual framepos_t get_preferred_edit_position(Editing::EditIgnoreOption=Editing::EDIT_IGNORE_NONE, bool from_context_menu=false, bool from_outside_canvas=false)=0
MidiRingBuffer< framepos_t > & step_edit_ring_buffer()
Definition: midi_track.h:105
int8_t last_added_pitch
Definition: step_editor.h:82
void set_note_range(VisibleNoteRange r)
uint8_t highest_note() const
StepEditor(PublicEditor &, boost::shared_ptr< ARDOUR::MidiTrack >, MidiTimeAxisView &)
Definition: step_editor.cc:35
void step_edit_rest(Evoral::Beats beats)
Definition: step_editor.cc:368
void start_step_editing()
Definition: step_editor.cc:59
LIBEVORAL_API uint64_t Beats
boost::shared_ptr< ARDOUR::MidiRegion > step_edit_region
Definition: step_editor.h:72
framecnt_t length() const
Definition: region.h:114
double frames_per_bar(const Tempo &, framecnt_t sr) const
Definition: tempo.cc:63
virtual framepos_t leftmost_sample() const =0
void region_removed(boost::weak_ptr< ARDOUR::Region >)
Definition: step_editor.cc:416
void check_step_edit()
Definition: step_editor.cc:177
void set_step_edit_cursor_width(Evoral::Beats beats)
Definition: step_editor.cc:324
const Tempo & tempo_at(framepos_t) const
Definition: tempo.cc:1617
MidiStreamView * midi_view()
bool step_editor_hidden(GdkEventAny *)
Definition: step_editor.cc:149
virtual void reset_x_origin(framepos_t frame)=0