#include "rgb_macros.h"
#include "selection.h"
#include "simplerect.h"
+#include "step_entry.h"
#include "utils.h"
#include "ardour/midi_track.h"
, _midi_thru_item (0)
, default_channel_menu (0)
, controller_menu (0)
+ , step_editor (0)
{
subplugin_menu.set_name ("ArdourContextMenu");
/* ask for notifications of any new RegionViews */
_view->RegionViewAdded.connect (sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
_view->attach ();
+
+ midi_track()->PlaylistChanged.connect (*this, invalidator (*this),
+ boost::bind (&MidiTimeAxisView::playlist_changed, this),
+ gui_context());
+ playlist_changed ();
+
}
HBox* midi_controls_hbox = manage(new HBox());
delete controller_menu;
}
+void
+MidiTimeAxisView::playlist_changed ()
+{
+ step_edit_region_connection.disconnect ();
+ midi_track()->playlist()->RegionRemoved.connect (step_edit_region_connection, invalidator (*this),
+ ui_bind (&MidiTimeAxisView::region_removed, this, _1),
+ gui_context());
+}
+
+void
+MidiTimeAxisView::region_removed (boost::weak_ptr<Region> wr)
+{
+ boost::shared_ptr<Region> r (wr.lock());
+
+ if (!r) {
+ return;
+ }
+
+ if (step_edit_region == r) {
+ step_edit_region.reset();
+ // force a recompute of the insert position
+ step_edit_beat_pos = -1.0;
+ }
+}
+
void MidiTimeAxisView::model_changed()
{
std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
MidiTimeAxisView::start_step_editing ()
{
step_edit_insert_position = _editor.get_preferred_edit_position ();
- step_edit_beat_pos = 0;
+ _step_edit_triplet_countdown = 0;
+ _step_edit_within_chord = 0;
+ _step_edit_chord_duration = 0.0;
+
step_edit_region = playlist()->top_region_at (step_edit_insert_position);
if (step_edit_region) {
RegionView* rv = view()->find_view (step_edit_region);
step_edit_region_view = dynamic_cast<MidiRegionView*> (rv);
+
} else {
- step_edit_region_view = 0;
- }
+ step_edit_region = add_region (step_edit_insert_position);
+ RegionView* rv = view()->find_view (step_edit_region);
+ step_edit_region_view = dynamic_cast<MidiRegionView*>(rv);
+ }
+
+ assert (step_edit_region);
+ assert (step_edit_region_view);
+
+ if (step_editor == 0) {
+ step_editor = new StepEntry (*this);
+ step_editor->signal_delete_event().connect (sigc::mem_fun (*this, &MidiTimeAxisView::step_editor_hidden));
+ step_editor->signal_hide().connect (sigc::mem_fun (*this, &MidiTimeAxisView::step_editor_hide));
+ }
+
+ framecnt_t frames_from_start = _editor.get_preferred_edit_position() - step_edit_region->position();
+
+ assert (frames_from_start >= 0);
- midi_track()->set_step_editing (true);
+ step_edit_beat_pos = step_edit_region_view->frames_to_beats (frames_from_start);
+
+ step_edit_region_view->show_step_edit_cursor (step_edit_beat_pos);
+ step_edit_region_view->set_step_edit_cursor_width (step_editor->note_length());
+
+ step_editor->set_position (WIN_POS_MOUSE);
+ step_editor->present ();
+}
+
+bool
+MidiTimeAxisView::step_editor_hidden (GdkEventAny*)
+{
+ step_editor_hide ();
+ return true;
}
void
-MidiTimeAxisView::stop_step_editing ()
+MidiTimeAxisView::step_editor_hide ()
{
+ /* everything else will follow the change in the model */
midi_track()->set_step_editing (false);
}
+void
+MidiTimeAxisView::stop_step_editing ()
+{
+ if (step_editor) {
+ step_editor->hide ();
+ }
+
+ if (step_edit_region_view) {
+ step_edit_region_view->hide_step_edit_cursor();
+ }
+}
+
void
MidiTimeAxisView::check_step_edit ()
{
MidiRingBuffer<nframes_t>& incoming (midi_track()->step_edit_ring_buffer());
- Evoral::Note<Evoral::MusicalTime> note;
uint8_t* buf;
uint32_t bufsize = 32;
incoming.read_contents (size, buf);
if ((buf[0] & 0xf0) == MIDI_CMD_NOTE_ON) {
+ step_add_note (buf[0] & 0xf, buf[1], buf[2], 0.0);
+ }
+ }
+}
- if (step_edit_region == 0) {
+int
+MidiTimeAxisView::step_add_bank_change (uint8_t channel, uint8_t bank)
+{
+ return 0;
+}
- step_edit_region = add_region (step_edit_insert_position);
- RegionView* rv = view()->find_view (step_edit_region);
+int
+MidiTimeAxisView::step_add_program_change (uint8_t channel, uint8_t program)
+{
+ return 0;
+}
- if (rv) {
- step_edit_region_view = dynamic_cast<MidiRegionView*>(rv);
- } else {
- fatal << X_("programming error: no view found for new MIDI region") << endmsg;
- /*NOTREACHED*/
- }
- }
+int
+MidiTimeAxisView::step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity, Evoral::MusicalTime beat_duration)
+{
+ if (step_edit_region && step_edit_region_view) {
+
+ if (beat_duration == 0.0) {
+ bool success;
+ beat_duration = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
+
+ if (!success) {
+ return -1;
+ }
+ }
+
+ MidiStreamView* msv = midi_view();
+
+ /* make sure its visible on the vertical axis */
+
+ if (pitch < msv->lowest_note() || pitch > msv->highest_note()) {
+ msv->update_note_range (pitch);
+ msv->set_note_range (MidiStreamView::ContentsRange);
+ }
+
+ /* make sure its visible on the horizontal axis */
+
+ nframes64_t fpos = step_edit_region->position() +
+ step_edit_region_view->beats_to_frames (step_edit_beat_pos + beat_duration);
+
+ if (fpos >= (_editor.leftmost_position() + _editor.current_page_frames())) {
+ _editor.reset_x_origin (fpos - (_editor.current_page_frames()/4));
+ }
+
+ step_edit_region_view->step_add_note (channel, pitch, velocity, step_edit_beat_pos, beat_duration);
+
+ if (_step_edit_triplet_countdown > 0) {
+ _step_edit_triplet_countdown--;
+
+ if (_step_edit_triplet_countdown == 0) {
+ _step_edit_triplet_countdown = 3;
+ }
+ }
+
+ if (!_step_edit_within_chord) {
+ step_edit_beat_pos += beat_duration;
+ step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
+ } else {
+ step_edit_beat_pos += 1.0/Meter::ticks_per_beat; // tiny, but no longer overlapping
+ _step_edit_chord_duration = max (_step_edit_chord_duration, beat_duration);
+ }
+ }
+
+ return 0;
+}
- if (step_edit_region_view) {
+void
+MidiTimeAxisView::set_step_edit_cursor_width (Evoral::MusicalTime beats)
+{
+ if (step_edit_region_view) {
+ step_edit_region_view->set_step_edit_cursor_width (beats);
+ }
+}
- bool success;
- Evoral::MusicalTime beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
+bool
+MidiTimeAxisView::step_edit_within_triplet() const
+{
+ return _step_edit_triplet_countdown > 0;
+}
- if (!success) {
- continue;
- }
+bool
+MidiTimeAxisView::step_edit_within_chord() const
+{
+ return _step_edit_within_chord;
+}
- step_edit_region_view->add_note (buf[0] & 0xf, buf[1], buf[2], step_edit_beat_pos, beats);
- step_edit_beat_pos += beats;
- }
- }
+void
+MidiTimeAxisView::step_edit_toggle_triplet ()
+{
+ if (_step_edit_triplet_countdown == 0) {
+ _step_edit_within_chord = false;
+ _step_edit_triplet_countdown = 3;
+ } else {
+ _step_edit_triplet_countdown = 0;
+ }
+}
- }
+void
+MidiTimeAxisView::step_edit_toggle_chord ()
+{
+ if (_step_edit_within_chord) {
+ _step_edit_within_chord = false;
+ step_edit_beat_pos += _step_edit_chord_duration;
+ step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
+ } else {
+ _step_edit_triplet_countdown = 0;
+ _step_edit_within_chord = true;
+ }
}
void
-MidiTimeAxisView::step_edit_rest ()
+MidiTimeAxisView::step_edit_rest (Evoral::MusicalTime beats)
{
bool success;
- Evoral::MusicalTime beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
- step_edit_beat_pos += beats;
+
+ if (beats == 0.0) {
+ beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
+ } else {
+ success = true;
+ }
+
+ if (success) {
+ step_edit_beat_pos += beats;
+ step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
+ }
+}
+
+void
+MidiTimeAxisView::step_edit_beat_sync ()
+{
+ step_edit_beat_pos = ceil (step_edit_beat_pos);
+ step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
+}
+
+void
+MidiTimeAxisView::step_edit_bar_sync ()
+{
+ if (!_session || !step_edit_region_view || !step_edit_region) {
+ return;
+ }
+
+ nframes64_t fpos = step_edit_region->position() +
+ step_edit_region_view->beats_to_frames (step_edit_beat_pos);
+ fpos = _session->tempo_map().round_to_bar (fpos, 1);
+ step_edit_beat_pos = ceil (step_edit_region_view->frames_to_beats (fpos - step_edit_region->position()));
+ step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
}
boost::shared_ptr<Region>
-MidiTimeAxisView::add_region (nframes64_t pos)
+MidiTimeAxisView::add_region (framepos_t pos)
{
Editor* real_editor = dynamic_cast<Editor*> (&_editor);