summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2010-08-15 16:39:51 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2010-08-15 16:39:51 +0000
commitfaca3e5f5d666fc543b23f6ab7b93a14f6c8ff7f (patch)
tree35d65ba93abd081308f659e590603d0a7d5645ab
parent66ea8edc6e317eba925558df7d8369ce5d260752 (diff)
split out the logic behind step editing from MidiTimeAxisView as much as possible
git-svn-id: svn://localhost/ardour2/branches/3.0@7633 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/midi_time_axis.cc440
-rw-r--r--gtk2_ardour/midi_time_axis.h37
-rw-r--r--gtk2_ardour/step_editor.cc395
-rw-r--r--gtk2_ardour/step_editor.h73
-rw-r--r--gtk2_ardour/step_entry.cc42
-rw-r--r--gtk2_ardour/step_entry.h6
-rw-r--r--gtk2_ardour/wscript1
7 files changed, 555 insertions, 439 deletions
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index 3eb7fff692..62beda8774 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -80,8 +80,8 @@
#include "region_view.h"
#include "rgb_macros.h"
#include "selection.h"
+#include "step_editor.h"
#include "simplerect.h"
-#include "step_entry.h"
#include "utils.h"
#include "ardour/midi_track.h"
@@ -116,7 +116,6 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
, _midi_thru_item (0)
, default_channel_menu (0)
, controller_menu (0)
- , step_editor (0)
{
subplugin_menu.set_name ("ArdourContextMenu");
@@ -127,8 +126,6 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
mute_button->set_active (false);
solo_button->set_active (false);
- step_edit_insert_position = 0;
-
if (is_midi_track()) {
controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
_note_mode = midi_track()->note_mode();
@@ -168,11 +165,6 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
_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());
@@ -235,35 +227,17 @@ MidiTimeAxisView::~MidiTimeAxisView ()
_range_scroomer = 0;
delete controller_menu;
+ delete _step_editor;
}
void
-MidiTimeAxisView::playlist_changed ()
+MidiTimeAxisView::check_step_edit ()
{
- 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());
+ _step_editor->check_step_edit ();
}
-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();
- step_edit_region_view = 0;
- // force a recompute of the insert position
- step_edit_beat_pos = -1.0;
- }
-}
-
-void MidiTimeAxisView::model_changed()
+void
+MidiTimeAxisView::model_changed()
{
std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
.custom_device_mode_names_by_model(_model_selector.get_active_text());
@@ -892,360 +866,7 @@ MidiTimeAxisView::route_active_changed ()
}
}
-void
-MidiTimeAxisView::start_step_editing ()
-{
- _step_edit_triplet_countdown = 0;
- _step_edit_within_chord = 0;
- _step_edit_chord_duration = 0.0;
- step_edit_region.reset ();
- step_edit_region_view = 0;
-
- resync_step_edit_position ();
- prepare_step_edit_region ();
- reset_step_edit_beat_pos ();
-
- 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));
- }
-
- 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 ();
-}
-
-void
-MidiTimeAxisView::resync_step_edit_position ()
-{
- step_edit_insert_position = _editor.get_preferred_edit_position ();
-}
-
-void
-MidiTimeAxisView::resync_step_edit_to_edit_point ()
-{
- resync_step_edit_position ();
- if (step_edit_region) {
- reset_step_edit_beat_pos ();
- }
-}
-
-void
-MidiTimeAxisView::prepare_step_edit_region ()
-{
- boost::shared_ptr<Region> r = playlist()->top_region_at (step_edit_insert_position);
-
- if (r) {
- step_edit_region = boost::dynamic_pointer_cast<MidiRegion>(r);
- }
-
- if (step_edit_region) {
- RegionView* rv = view()->find_view (step_edit_region);
- step_edit_region_view = dynamic_cast<MidiRegionView*> (rv);
-
- } else {
- 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);
- }
-}
-
-
-void
-MidiTimeAxisView::reset_step_edit_beat_pos ()
-{
- assert (step_edit_region);
- assert (step_edit_region_view);
-
- framecnt_t frames_from_start = _editor.get_preferred_edit_position() - step_edit_region->position();
-
- if (frames_from_start < 0) {
- /* this can happen with snap enabled, and the edit point == Playhead. we snap the
- position of the new region, and it can end up after the edit point.
- */
- frames_from_start = 0;
- }
-
- step_edit_beat_pos = step_edit_region_view->frames_to_beats (frames_from_start);
- step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
-}
-
-bool
-MidiTimeAxisView::step_editor_hidden (GdkEventAny*)
-{
- step_editor_hide ();
- return true;
-}
-
-void
-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();
- }
-
- step_edit_region.reset ();
-}
-
-void
-MidiTimeAxisView::check_step_edit ()
-{
- MidiRingBuffer<nframes_t>& incoming (midi_track()->step_edit_ring_buffer());
- uint8_t* buf;
- uint32_t bufsize = 32;
-
- buf = new uint8_t[bufsize];
-
- while (incoming.read_space()) {
- nframes_t time;
- Evoral::EventType type;
- uint32_t size;
-
- incoming.read_prefix (&time, &type, &size);
-
- if (size > bufsize) {
- delete [] buf;
- bufsize = size;
- buf = new uint8_t[bufsize];
- }
-
- 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);
- }
- }
-}
-
-int
-MidiTimeAxisView::step_add_bank_change (uint8_t channel, uint8_t bank)
-{
- return 0;
-}
-
-int
-MidiTimeAxisView::step_add_program_change (uint8_t channel, uint8_t program)
-{
- return 0;
-}
-
-void
-MidiTimeAxisView::step_edit_sustain (Evoral::MusicalTime beats)
-{
- if (step_edit_region_view) {
- step_edit_region_view->step_sustain (beats);
- }
-}
-
-void
-MidiTimeAxisView::move_step_edit_beat_pos (Evoral::MusicalTime beats)
-{
- if (beats > 0.0) {
- step_edit_beat_pos = min (step_edit_beat_pos + beats,
- step_edit_region_view->frames_to_beats (step_edit_region->length()));
- } else if (beats < 0.0) {
- if (beats < step_edit_beat_pos) {
- step_edit_beat_pos += beats; // its negative, remember
- } else {
- step_edit_beat_pos = 0;
- }
- }
- step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
-}
-
-int
-MidiTimeAxisView::step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity, Evoral::MusicalTime beat_duration)
-{
- /* do these things in case undo removed the step edit region
- */
- if (!step_edit_region) {
- resync_step_edit_position ();
- prepare_step_edit_region ();
- reset_step_edit_beat_pos ();
- 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());
- }
-
- assert (step_edit_region);
- assert (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;
-}
-
-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
-MidiTimeAxisView::step_edit_within_triplet() const
-{
- return _step_edit_triplet_countdown > 0;
-}
-
-bool
-MidiTimeAxisView::step_edit_within_chord() const
-{
- return _step_edit_within_chord;
-}
-
-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 (Evoral::MusicalTime beats)
-{
- bool success;
-
- 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;
- }
-
- framepos_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<MidiRegion>
-MidiTimeAxisView::add_region (framepos_t pos)
-{
- Editor* real_editor = dynamic_cast<Editor*> (&_editor);
-
- real_editor->begin_reversible_command (_("create region"));
- playlist()->clear_history ();
-
- real_editor->snap_to (pos, 0);
- const Meter& m = _session->tempo_map().meter_at(pos);
- const Tempo& t = _session->tempo_map().tempo_at(pos);
- double length = floor (m.frames_per_bar(t, _session->frame_rate()));
-
- boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
- view()->trackview().track()->name());
- PropertyList plist;
-
- plist.add (ARDOUR::Properties::start, 0);
- plist.add (ARDOUR::Properties::length, length);
- plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
-
- boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
-
- playlist()->add_region (region, pos);
- _session->add_command (new StatefulDiffCommand (playlist()));
-
- real_editor->commit_reversible_command();
- return boost::dynamic_pointer_cast<MidiRegion>(region);
-}
void
MidiTimeAxisView::add_note_selection (uint8_t note)
@@ -1380,3 +1001,52 @@ MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
return 0;
}
+
+boost::shared_ptr<MidiRegion>
+MidiTimeAxisView::add_region (framepos_t pos)
+{
+ Editor* real_editor = dynamic_cast<Editor*> (&_editor);
+
+ real_editor->begin_reversible_command (_("create region"));
+ playlist()->clear_history ();
+
+ real_editor->snap_to (pos, 0);
+ const Meter& m = _session->tempo_map().meter_at(pos);
+ const Tempo& t = _session->tempo_map().tempo_at(pos);
+ double length = floor (m.frames_per_bar(t, _session->frame_rate()));
+
+ boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
+ view()->trackview().track()->name());
+ PropertyList plist;
+
+ plist.add (ARDOUR::Properties::start, 0);
+ plist.add (ARDOUR::Properties::length, length);
+ plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
+
+ boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
+
+ playlist()->add_region (region, pos);
+ _session->add_command (new StatefulDiffCommand (playlist()));
+
+ real_editor->commit_reversible_command();
+
+ return boost::dynamic_pointer_cast<MidiRegion>(region);
+}
+
+void
+MidiTimeAxisView::start_step_editing ()
+{
+ if (!_step_editor) {
+ _step_editor = new StepEditor (_editor, midi_track(), *this);
+ }
+
+ _step_editor->start_step_editing ();
+
+}
+void
+MidiTimeAxisView::stop_step_editing ()
+{
+ if (_step_editor) {
+ _step_editor->stop_step_editing ();
+ }
+}
diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h
index 63372b9218..73c48f2613 100644
--- a/gtk2_ardour/midi_time_axis.h
+++ b/gtk2_ardour/midi_time_axis.h
@@ -54,6 +54,7 @@ class MidiStreamView;
class MidiScroomer;
class PianoRollHeader;
class StepEntry;
+class StepEditor;
class MidiTimeAxisView : public RouteTimeAxisView
{
@@ -87,28 +88,14 @@ class MidiTimeAxisView : public RouteTimeAxisView
return _midi_patch_settings_changed;
}
- void check_step_edit ();
- void step_edit_rest (Evoral::MusicalTime beats);
- void step_edit_beat_sync ();
- void step_edit_bar_sync ();
- int step_add_bank_change (uint8_t channel, uint8_t bank);
- int step_add_program_change (uint8_t channel, uint8_t program);
- int step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity,
- Evoral::MusicalTime beat_duration);
- void step_edit_sustain (Evoral::MusicalTime beats);
- bool step_edit_within_triplet () const;
- void step_edit_toggle_triplet ();
- bool step_edit_within_chord () const;
- void step_edit_toggle_chord ();
- void reset_step_edit_beat_pos ();
- void resync_step_edit_to_edit_point ();
- void move_step_edit_beat_pos (Evoral::MusicalTime beats);
- void set_step_edit_cursor_width (Evoral::MusicalTime beats);
const MidiMultipleChannelSelector& channel_selector() { return _channel_selector; }
Gtk::CheckMenuItem* automation_child_menu_item (Evoral::Parameter);
+ StepEditor* step_editor() { return _step_editor; }
+ void check_step_edit ();
+
protected:
void start_step_editing ();
void stop_step_editing ();
@@ -149,16 +136,6 @@ class MidiTimeAxisView : public RouteTimeAxisView
Gtk::CheckMenuItem* _midi_thru_item;
Gtk::Menu* default_channel_menu;
- nframes64_t step_edit_insert_position;
- Evoral::MusicalTime step_edit_beat_pos;
- boost::shared_ptr<ARDOUR::MidiRegion> step_edit_region;
- MidiRegionView* step_edit_region_view;
- uint8_t _step_edit_triplet_countdown;
- bool _step_edit_within_chord;
- Evoral::MusicalTime _step_edit_chord_duration;
- void region_removed (boost::weak_ptr<ARDOUR::Region>);
- void playlist_changed ();
- PBD::ScopedConnection step_edit_region_connection;
Gtk::Menu* build_def_channel_menu();
void set_default_channel (int);
@@ -184,11 +161,7 @@ class MidiTimeAxisView : public RouteTimeAxisView
/** parameter -> menu item map for the controller menu */
ParameterMenuMap _controller_menu_map;
- StepEntry* step_editor;
- bool step_editor_hidden (GdkEventAny*);
- void step_editor_hide ();
- void resync_step_edit_position ();
- void prepare_step_edit_region ();
+ StepEditor* _step_editor;
};
#endif /* __ardour_midi_time_axis_h__ */
diff --git a/gtk2_ardour/step_editor.cc b/gtk2_ardour/step_editor.cc
new file mode 100644
index 0000000000..822af4c559
--- /dev/null
+++ b/gtk2_ardour/step_editor.cc
@@ -0,0 +1,395 @@
+#include "ardour/midi_track.h"
+#include "ardour/midi_region.h"
+#include "ardour/tempo.h"
+#include "ardour/types.h"
+
+#include "gui_thread.h"
+#include "midi_region_view.h"
+#include "public_editor.h"
+#include "step_editor.h"
+#include "step_entry.h"
+
+using namespace ARDOUR;
+using namespace Gtk;
+using namespace std;
+
+StepEditor::StepEditor (PublicEditor& e, boost::shared_ptr<MidiTrack> t, MidiTimeAxisView& mtv)
+ : _editor (e)
+ , _track (t)
+ , step_editor (0)
+ , _mtv (mtv)
+{
+ step_edit_insert_position = 0;
+ _step_edit_triplet_countdown = 0;
+ _step_edit_within_chord = 0;
+ _step_edit_chord_duration = 0.0;
+ step_edit_region_view = 0;
+
+ _track->PlaylistChanged.connect (*this, invalidator (*this),
+ boost::bind (&StepEditor::playlist_changed, this),
+ gui_context());
+ playlist_changed ();
+}
+
+StepEditor::~StepEditor()
+{
+ delete step_editor;
+}
+
+void
+StepEditor::start_step_editing ()
+{
+ _step_edit_triplet_countdown = 0;
+ _step_edit_within_chord = 0;
+ _step_edit_chord_duration = 0.0;
+ step_edit_region.reset ();
+ step_edit_region_view = 0;
+
+ resync_step_edit_position ();
+ prepare_step_edit_region ();
+ reset_step_edit_beat_pos ();
+
+ 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, &StepEditor::step_editor_hidden));
+ step_editor->signal_hide().connect (sigc::mem_fun (*this, &StepEditor::step_editor_hide));
+ }
+
+ 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 ();
+}
+
+void
+StepEditor::resync_step_edit_position ()
+{
+ step_edit_insert_position = _editor.get_preferred_edit_position ();
+}
+
+void
+StepEditor::resync_step_edit_to_edit_point ()
+{
+ resync_step_edit_position ();
+ if (step_edit_region) {
+ reset_step_edit_beat_pos ();
+ }
+}
+
+void
+StepEditor::prepare_step_edit_region ()
+{
+ boost::shared_ptr<Region> r = _track->playlist()->top_region_at (step_edit_insert_position);
+
+ if (r) {
+ step_edit_region = boost::dynamic_pointer_cast<MidiRegion>(r);
+ }
+
+ if (step_edit_region) {
+ RegionView* rv = _mtv.midi_view()->find_view (step_edit_region);
+ step_edit_region_view = dynamic_cast<MidiRegionView*> (rv);
+
+ } else {
+ step_edit_region = _mtv.add_region (step_edit_insert_position);
+ RegionView* rv = _mtv.midi_view()->find_view (step_edit_region);
+ step_edit_region_view = dynamic_cast<MidiRegionView*>(rv);
+ }
+}
+
+
+void
+StepEditor::reset_step_edit_beat_pos ()
+{
+ assert (step_edit_region);
+ assert (step_edit_region_view);
+
+ framecnt_t frames_from_start = _editor.get_preferred_edit_position() - step_edit_region->position();
+
+ if (frames_from_start < 0) {
+ /* this can happen with snap enabled, and the edit point == Playhead. we snap the
+ position of the new region, and it can end up after the edit point.
+ */
+ frames_from_start = 0;
+ }
+
+ step_edit_beat_pos = step_edit_region_view->frames_to_beats (frames_from_start);
+ step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
+}
+
+bool
+StepEditor::step_editor_hidden (GdkEventAny*)
+{
+ step_editor_hide ();
+ return true;
+}
+
+void
+StepEditor::step_editor_hide ()
+{
+ /* everything else will follow the change in the model */
+ _track->set_step_editing (false);
+}
+
+void
+StepEditor::stop_step_editing ()
+{
+ if (step_editor) {
+ step_editor->hide ();
+ }
+
+ if (step_edit_region_view) {
+ step_edit_region_view->hide_step_edit_cursor();
+ }
+
+ step_edit_region.reset ();
+}
+
+void
+StepEditor::check_step_edit ()
+{
+ MidiRingBuffer<nframes_t>& incoming (_track->step_edit_ring_buffer());
+ uint8_t* buf;
+ uint32_t bufsize = 32;
+
+ buf = new uint8_t[bufsize];
+
+ while (incoming.read_space()) {
+ nframes_t time;
+ Evoral::EventType type;
+ uint32_t size;
+
+ incoming.read_prefix (&time, &type, &size);
+
+ if (size > bufsize) {
+ delete [] buf;
+ bufsize = size;
+ buf = new uint8_t[bufsize];
+ }
+
+ 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);
+ }
+ }
+}
+
+int
+StepEditor::step_add_bank_change (uint8_t channel, uint8_t bank)
+{
+ return 0;
+}
+
+int
+StepEditor::step_add_program_change (uint8_t channel, uint8_t program)
+{
+ return 0;
+}
+
+void
+StepEditor::step_edit_sustain (Evoral::MusicalTime beats)
+{
+ if (step_edit_region_view) {
+ step_edit_region_view->step_sustain (beats);
+ }
+}
+
+void
+StepEditor::move_step_edit_beat_pos (Evoral::MusicalTime beats)
+{
+ if (beats > 0.0) {
+ step_edit_beat_pos = min (step_edit_beat_pos + beats,
+ step_edit_region_view->frames_to_beats (step_edit_region->length()));
+ } else if (beats < 0.0) {
+ if (beats < step_edit_beat_pos) {
+ step_edit_beat_pos += beats; // its negative, remember
+ } else {
+ step_edit_beat_pos = 0;
+ }
+ }
+ step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
+}
+
+int
+StepEditor::step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity, Evoral::MusicalTime beat_duration)
+{
+ /* do these things in case undo removed the step edit region
+ */
+ if (!step_edit_region) {
+ resync_step_edit_position ();
+ prepare_step_edit_region ();
+ reset_step_edit_beat_pos ();
+ 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());
+ }
+
+ assert (step_edit_region);
+ assert (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 = _mtv.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;
+}
+
+void
+StepEditor::set_step_edit_cursor_width (Evoral::MusicalTime beats)
+{
+ if (step_edit_region_view) {
+ step_edit_region_view->set_step_edit_cursor_width (beats);
+ }
+}
+
+bool
+StepEditor::step_edit_within_triplet() const
+{
+ return _step_edit_triplet_countdown > 0;
+}
+
+bool
+StepEditor::step_edit_within_chord() const
+{
+ return _step_edit_within_chord;
+}
+
+void
+StepEditor::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
+StepEditor::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
+StepEditor::step_edit_rest (Evoral::MusicalTime beats)
+{
+ bool success;
+
+ 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
+StepEditor::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
+StepEditor::step_edit_bar_sync ()
+{
+ Session* _session = _mtv.session ();
+
+ if (!_session || !step_edit_region_view || !step_edit_region) {
+ return;
+ }
+
+ framepos_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);
+}
+
+void
+StepEditor::playlist_changed ()
+{
+ step_edit_region_connection.disconnect ();
+ _track->playlist()->RegionRemoved.connect (step_edit_region_connection, invalidator (*this),
+ ui_bind (&StepEditor::region_removed, this, _1),
+ gui_context());
+}
+
+void
+StepEditor::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();
+ step_edit_region_view = 0;
+ // force a recompute of the insert position
+ step_edit_beat_pos = -1.0;
+ }
+}
+
+string
+StepEditor::name() const
+{
+ return _track->name();
+}
diff --git a/gtk2_ardour/step_editor.h b/gtk2_ardour/step_editor.h
new file mode 100644
index 0000000000..00be7890a3
--- /dev/null
+++ b/gtk2_ardour/step_editor.h
@@ -0,0 +1,73 @@
+#ifndef __pbd__step_editor_h__
+#define __pbd__step_editor_h__
+
+#include <string>
+
+#include <gdk/gdk.h>
+#include <sigc++/trackable.h>
+
+#include "pbd/signals.h"
+#include "evoral/types.hpp"
+
+namespace ARDOUR {
+ class MidiTrack;
+ class MidiRegion;
+}
+
+class MidiRegionView;
+class MidiTimeAxisView;
+class PublicEditor;
+class StepEntry;
+
+class StepEditor : public PBD::ScopedConnectionList, public sigc::trackable
+{
+ public:
+ StepEditor (PublicEditor&, boost::shared_ptr<ARDOUR::MidiTrack>, MidiTimeAxisView&);
+ virtual ~StepEditor ();
+
+ void check_step_edit ();
+ void step_edit_rest (Evoral::MusicalTime beats);
+ void step_edit_beat_sync ();
+ void step_edit_bar_sync ();
+ int step_add_bank_change (uint8_t channel, uint8_t bank);
+ int step_add_program_change (uint8_t channel, uint8_t program);
+ int step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity,
+ Evoral::MusicalTime beat_duration);
+ void step_edit_sustain (Evoral::MusicalTime beats);
+ bool step_edit_within_triplet () const;
+ void step_edit_toggle_triplet ();
+ bool step_edit_within_chord () const;
+ void step_edit_toggle_chord ();
+ void reset_step_edit_beat_pos ();
+ void resync_step_edit_to_edit_point ();
+ void move_step_edit_beat_pos (Evoral::MusicalTime beats);
+ void set_step_edit_cursor_width (Evoral::MusicalTime beats);
+
+ std::string name() const;
+
+ void start_step_editing ();
+ void stop_step_editing ();
+
+ private:
+ ARDOUR::framepos_t step_edit_insert_position;
+ Evoral::MusicalTime step_edit_beat_pos;
+ boost::shared_ptr<ARDOUR::MidiRegion> step_edit_region;
+ MidiRegionView* step_edit_region_view;
+ uint8_t _step_edit_triplet_countdown;
+ bool _step_edit_within_chord;
+ Evoral::MusicalTime _step_edit_chord_duration;
+ PBD::ScopedConnection step_edit_region_connection;
+ PublicEditor& _editor;
+ boost::shared_ptr<ARDOUR::MidiTrack> _track;
+ StepEntry* step_editor;
+ MidiTimeAxisView& _mtv;
+
+ void region_removed (boost::weak_ptr<ARDOUR::Region>);
+ void playlist_changed ();
+ bool step_editor_hidden (GdkEventAny*);
+ void step_editor_hide ();
+ void resync_step_edit_position ();
+ void prepare_step_edit_region ();
+};
+
+#endif /* __pbd__step_editor_h__ */
diff --git a/gtk2_ardour/step_entry.cc b/gtk2_ardour/step_entry.cc
index d3ecca434c..1fd6b37cfb 100644
--- a/gtk2_ardour/step_entry.cc
+++ b/gtk2_ardour/step_entry.cc
@@ -31,6 +31,7 @@
#include "ardour_ui.h"
#include "midi_channel_selector.h"
#include "midi_time_axis.h"
+#include "step_editor.h"
#include "step_entry.h"
#include "utils.h"
@@ -55,8 +56,8 @@ _rest_event_handler (GtkWidget* widget, gpointer arg)
((StepEntry*)arg)->rest_event_handler ();
}
-StepEntry::StepEntry (MidiTimeAxisView& mtv)
- : ArdourDialog (string_compose (_("Step Entry: %1"), mtv.name()))
+StepEntry::StepEntry (StepEditor& seditor)
+ : ArdourDialog (string_compose (_("Step Entry: %1"), seditor.name()))
, _current_note_length (1.0)
, _current_note_velocity (64)
, triplet_button ("3")
@@ -84,17 +85,18 @@ StepEntry::StepEntry (MidiTimeAxisView& mtv)
, program_button (_("+"))
, _piano (0)
, piano (0)
- , _mtv (&mtv)
+ , se (&seditor)
{
register_actions ();
load_bindings ();
+#if 0
/* set channel selector to first selected channel. if none
are selected, it will remain at the value set in its
constructor, above (1)
*/
- uint16_t chn_mask = _mtv->channel_selector().get_selected_channels();
+ uint16_t chn_mask = se->channel_selector().get_selected_channels();
for (uint32_t i = 0; i < 16; ++i) {
if (chn_mask & (1<<i)) {
@@ -103,6 +105,8 @@ StepEntry::StepEntry (MidiTimeAxisView& mtv)
}
}
+#endif
+
RadioButtonGroup length_group = length_1_button.get_group();
length_2_button.set_group (length_group);
length_4_button.set_group (length_group);
@@ -510,7 +514,7 @@ StepEntry::on_key_release_event (GdkEventKey* ev)
void
StepEntry::rest_event_handler ()
{
- _mtv->step_edit_rest (0.0);
+ se->step_edit_rest (0.0);
}
Evoral::MusicalTime
@@ -565,13 +569,13 @@ StepEntry::on_show ()
void
StepEntry::beat_resync_click ()
{
- _mtv->step_edit_beat_sync ();
+ se->step_edit_beat_sync ();
}
void
StepEntry::bar_resync_click ()
{
- _mtv->step_edit_bar_sync ();
+ se->step_edit_bar_sync ();
}
void
@@ -703,13 +707,13 @@ StepEntry::load_bindings ()
void
StepEntry::toggle_triplet ()
{
- _mtv->set_step_edit_cursor_width (note_length());
+ se->set_step_edit_cursor_width (note_length());
}
void
StepEntry::toggle_chord ()
{
- _mtv->step_edit_toggle_chord ();
+ se->step_edit_toggle_chord ();
}
void
@@ -756,37 +760,37 @@ StepEntry::dot_value_change ()
dot2_button.set_inconsistent (inconsistent);
dot3_button.set_inconsistent (inconsistent);
- _mtv->set_step_edit_cursor_width (note_length());
+ se->set_step_edit_cursor_width (note_length());
}
void
StepEntry::program_click ()
{
- _mtv->step_add_program_change (note_channel(), (int8_t) floor (program_adjustment.get_value()));
+ se->step_add_program_change (note_channel(), (int8_t) floor (program_adjustment.get_value()));
}
void
StepEntry::bank_click ()
{
- _mtv->step_add_bank_change (note_channel(), (int8_t) floor (bank_adjustment.get_value()));
+ se->step_add_bank_change (note_channel(), (int8_t) floor (bank_adjustment.get_value()));
}
void
StepEntry::insert_rest ()
{
- _mtv->step_edit_rest (note_length());
+ se->step_edit_rest (note_length());
}
void
StepEntry::insert_grid_rest ()
{
- _mtv->step_edit_rest (0.0);
+ se->step_edit_rest (0.0);
}
void
StepEntry::insert_note (uint8_t note)
{
- _mtv->step_add_note (note_channel(), note, note_velocity(), note_length());
+ se->step_add_note (note_channel(), note, note_velocity(), note_length());
}
void
StepEntry::insert_c ()
@@ -972,7 +976,7 @@ StepEntry::length_value_change ()
length_32_button.set_inconsistent (inconsistent);
length_64_button.set_inconsistent (inconsistent);
- _mtv->set_step_edit_cursor_width (note_length());
+ se->set_step_edit_cursor_width (note_length());
}
bool
@@ -1132,17 +1136,17 @@ StepEntry::octave_n (int n)
void
StepEntry::do_sustain ()
{
- _mtv->step_edit_sustain (note_length());
+ se->step_edit_sustain (note_length());
}
void
StepEntry::back ()
{
- _mtv->move_step_edit_beat_pos (-note_length());
+ se->move_step_edit_beat_pos (-note_length());
}
void
StepEntry::sync_to_edit_point ()
{
- _mtv->resync_step_edit_to_edit_point ();
+ se->resync_step_edit_to_edit_point ();
}
diff --git a/gtk2_ardour/step_entry.h b/gtk2_ardour/step_entry.h
index 934e5e5c18..e534c83e01 100644
--- a/gtk2_ardour/step_entry.h
+++ b/gtk2_ardour/step_entry.h
@@ -30,12 +30,12 @@
#include "ardour_dialog.h"
#include "gtk_pianokeyboard.h"
-class MidiTimeAxisView;
+class StepEditor;
class StepEntry : public ArdourDialog
{
public:
- StepEntry (MidiTimeAxisView&);
+ StepEntry (StepEditor&);
~StepEntry ();
void note_off_event_handler (int note);
@@ -124,7 +124,7 @@ class StepEntry : public ArdourDialog
PianoKeyboard* _piano;
Gtk::Widget* piano;
- MidiTimeAxisView* _mtv;
+ StepEditor* se;
void bank_click ();
void program_click ();
diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript
index 5ec8ac5726..d87e31a604 100644
--- a/gtk2_ardour/wscript
+++ b/gtk2_ardour/wscript
@@ -190,6 +190,7 @@ gtk2_ardour_sources = [
'simplerect.cc',
'splash.cc',
'startup.cc',
+ 'step_editor.cc',
'step_entry.cc',
'streamview.cc',
'strip_silence_dialog.cc',