diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2009-09-03 12:39:50 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2009-09-03 12:39:50 +0000 |
commit | b0b584c2a595bfdf6bb4b980bd8d8fc7f3546fc5 (patch) | |
tree | 0bbe7220f24b7e7cefadc546d19c409ea357820f | |
parent | c8932292e19f31cab856096c94788bd3f6c5b5fc (diff) |
the basics of step editing, more details to follow
git-svn-id: svn://localhost/ardour2/branches/3.0@5629 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r-- | gtk2_ardour/editor_drag.cc | 31 | ||||
-rw-r--r-- | gtk2_ardour/export_file_notebook.cc | 3 | ||||
-rw-r--r-- | gtk2_ardour/midi_list_editor.cc | 57 | ||||
-rw-r--r-- | gtk2_ardour/midi_list_editor.h | 14 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.cc | 27 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.h | 3 | ||||
-rw-r--r-- | gtk2_ardour/midi_time_axis.cc | 175 | ||||
-rw-r--r-- | gtk2_ardour/midi_time_axis.h | 16 | ||||
-rw-r--r-- | gtk2_ardour/route_time_axis.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/route_ui.cc | 29 | ||||
-rw-r--r-- | gtk2_ardour/route_ui.h | 4 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_track.h | 10 | ||||
-rw-r--r-- | libs/ardour/ardour/tempo.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/track.h | 4 | ||||
-rw-r--r-- | libs/ardour/midi_track.cc | 48 |
15 files changed, 367 insertions, 58 deletions
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index a8557dee4e..be261a5de0 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -1366,46 +1366,19 @@ void RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred) { MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview); - if (!mtv) { - return; - } - const boost::shared_ptr<MidiDiskstream> diskstream = - boost::dynamic_pointer_cast<MidiDiskstream>(mtv->view()->trackview().track()->diskstream()); - - if (!diskstream) { - warning << "Cannot create non-MIDI region" << endl; + if (!mtv) { return; } if (!movement_occurred) { - _editor->begin_reversible_command (_("create region")); - XMLNode &before = mtv->playlist()->get_state(); - - nframes64_t start = _grab_frame; - _editor->snap_to (start, -1); - const Meter& m = _editor->session->tempo_map().meter_at(start); - const Tempo& t = _editor->session->tempo_map().tempo_at(start); - double length = floor (m.frames_per_bar(t, _editor->session->frame_rate())); - - boost::shared_ptr<Source> src = _editor->session->create_midi_source_for_session(*diskstream.get()); - - mtv->playlist()->add_region (boost::dynamic_pointer_cast<MidiRegion> - (RegionFactory::create(src, 0, (nframes_t) length, - PBD::basename_nosuffix(src->name()))), start); - XMLNode &after = mtv->playlist()->get_state(); - _editor->session->add_command(new MementoCommand<Playlist>(*mtv->playlist().get(), &before, &after)); - _editor->commit_reversible_command(); - + mtv->add_region (_grab_frame); } else { motion (event, false); // TODO: create region-create-drag region here } } - - - void RegionGainDrag::motion (GdkEvent* /*event*/, bool) { diff --git a/gtk2_ardour/export_file_notebook.cc b/gtk2_ardour/export_file_notebook.cc index b10c0e58c1..9b5136c9a4 100644 --- a/gtk2_ardour/export_file_notebook.cc +++ b/gtk2_ardour/export_file_notebook.cc @@ -32,7 +32,8 @@ ExportFileNotebook::ExportFileNotebook () : { /* Last page */ - new_file_button.add (*Gtk::manage (new Gtk::Image (::get_icon("add")))); + new_file_button.set_image (*Gtk::manage (new Gtk::Image (::get_icon("add")))); + new_file_button.set_label (_(" Click here to add another format")); new_file_button.set_alignment (0, 0.5); new_file_button.set_relief (Gtk::RELIEF_NONE); diff --git a/gtk2_ardour/midi_list_editor.cc b/gtk2_ardour/midi_list_editor.cc index 2db6cbd25e..d4a751192a 100644 --- a/gtk2_ardour/midi_list_editor.cc +++ b/gtk2_ardour/midi_list_editor.cc @@ -19,6 +19,8 @@ #include "evoral/midi_util.h" #include "ardour/midi_region.h" +#include "ardour/session.h" +#include "ardour/tempo.h" #include "midi_list_editor.h" @@ -29,20 +31,21 @@ using namespace Gtk; using namespace Glib; using namespace ARDOUR; -MidiListEditor::MidiListEditor (boost::shared_ptr<MidiRegion> r) +MidiListEditor::MidiListEditor (Session& s, boost::shared_ptr<MidiRegion> r) : ArdourDialog (r->name(), false, false) + , session (s) , region (r) { model = ListStore::create (columns); view.set_model (model); + view.append_column (_("Start"), columns.start); view.append_column (_("Channel"), columns.channel); - view.append_column (_("Note"), columns.note); + view.append_column (_("Num"), columns.note); view.append_column (_("Name"), columns.note_name); - view.append_column (_("Velocity"), columns.velocity); - view.append_column (_("Start"), columns.start); - view.append_column (_("End"), columns.end); + view.append_column (_("Vel"), columns.velocity); view.append_column (_("Length"), columns.length); + view.append_column (_("End"), columns.end); view.set_headers_visible (true); view.set_name (X_("MidiListView")); view.set_rules_hint (true); @@ -70,8 +73,20 @@ MidiListEditor::~MidiListEditor () } void -MidiListEditor::edited (const Glib::ustring& /* path */, const Glib::ustring& /* text */) +MidiListEditor::edited (const Glib::ustring& path, const Glib::ustring& /* text */) { + TreeModel::iterator iter = model->get_iter (path); + + cerr << "Edit at " << path << endl; + + if (!iter) { + return; + } + + boost::shared_ptr<NoteType> note = (*iter)[columns._note]; + + cerr << "Edited " << *note << endl; + redisplay_model (); } @@ -87,12 +102,34 @@ MidiListEditor::redisplay_model () for (MidiModel::Notes::iterator i = notes.begin(); i != notes.end(); ++i) { row = *(model->append()); row[columns.channel] = (*i)->channel(); - row[columns.note_name] = Evoral::midi_note_name ((*i)->note()); + row[columns.note_name] = _("Note"); row[columns.note] = (*i)->note(); row[columns.velocity] = (*i)->velocity(); - row[columns.start] = (*i)->time(); - row[columns.length] = (*i)->length(); - row[columns.end] = (*i)->end_time(); + + BBT_Time bbt; + BBT_Time dur; + stringstream ss; + + session.tempo_map().bbt_time (region->position(), bbt); + + dur.bars = 0; + dur.beats = floor ((*i)->time()); + dur.ticks = 0; + + session.tempo_map().bbt_duration_at (region->position(), dur, 0); + + ss << bbt; + row[columns.start] = ss.str(); + ss << dur; + row[columns.length] = ss.str(); + + session.tempo_map().bbt_time (region->position(), bbt); + /* XXX get end point */ + + ss << bbt; + row[columns.end] = ss.str(); + + row[columns._note] = (*i); } view.set_model (model); diff --git a/gtk2_ardour/midi_list_editor.h b/gtk2_ardour/midi_list_editor.h index ac931dcca6..d52c1d83ac 100644 --- a/gtk2_ardour/midi_list_editor.h +++ b/gtk2_ardour/midi_list_editor.h @@ -31,12 +31,15 @@ namespace ARDOUR { class MidiRegion; class MidiModel; + class Session; }; class MidiListEditor : public ArdourDialog { public: - MidiListEditor(boost::shared_ptr<ARDOUR::MidiRegion>); + typedef Evoral::Note<Evoral::MusicalTime> NoteType; + + MidiListEditor(ARDOUR::Session&, boost::shared_ptr<ARDOUR::MidiRegion>); ~MidiListEditor(); private: @@ -49,16 +52,19 @@ class MidiListEditor : public ArdourDialog add (start); add (length); add (end); + add (note); }; Gtk::TreeModelColumn<uint8_t> channel; Gtk::TreeModelColumn<uint8_t> note; Gtk::TreeModelColumn<std::string> note_name; Gtk::TreeModelColumn<uint8_t> velocity; - Gtk::TreeModelColumn<Evoral::MusicalTime> start; - Gtk::TreeModelColumn<Evoral::MusicalTime> length; - Gtk::TreeModelColumn<Evoral::MusicalTime> end; + Gtk::TreeModelColumn<std::string> start; + Gtk::TreeModelColumn<std::string> length; + Gtk::TreeModelColumn<std::string> end; + Gtk::TreeModelColumn<boost::shared_ptr<NoteType> > _note; }; + ARDOUR::Session& session; MidiListModelColumns columns; Glib::RefPtr<Gtk::ListStore> model; Gtk::TreeView view; diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 317e1f33fe..d3af36ab92 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -500,7 +500,7 @@ MidiRegionView::canvas_event(GdkEvent* ev) void MidiRegionView::show_list_editor () { - MidiListEditor* mle = new MidiListEditor (midi_region()); + MidiListEditor* mle = new MidiListEditor (trackview.session(), midi_region()); mle->show (); } @@ -761,6 +761,7 @@ MidiRegionView::display_sysexes() string text = str.str(); ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group(); + const double x = trackview.editor().frame_to_pixel(beats_to_frames(time)); double height = midi_stream_view()->contents_height(); @@ -2236,6 +2237,30 @@ MidiRegionView::paste (nframes64_t pos, float times, const MidiCutBuffer& mcb) } void +MidiRegionView::add_note (uint8_t channel, uint8_t number, uint8_t velocity, + Evoral::MusicalTime pos, Evoral::MusicalTime len) +{ + boost::shared_ptr<NoteType> new_note (new NoteType (channel, pos, len, number, velocity)); + + start_delta_command (_("step add")); + command_add_note (new_note, true, false); + apply_command (); + + /* potentially extend region to hold new note */ + + + nframes64_t end_frame = _region->position() + beats_to_frames (new_note->length()); + nframes64_t region_end = _region->position() + _region->length() - 1; + + if (end_frame > region_end) { + cerr << "Resize region!\n"; + _region->set_length (end_frame, this); + } else { + redisplay_model (); + } +} + +void MidiRegionView::goto_next_note () { // nframes64_t pos = -1; diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index b88583e64e..c32fd2cb69 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -88,6 +88,9 @@ class MidiRegionView : public RegionView inline MidiStreamView* midi_stream_view() const { return midi_view()->midi_view(); } + void add_note (uint8_t channel, uint8_t number, uint8_t velocity, + Evoral::MusicalTime pos, Evoral::MusicalTime len); + void set_height (double); void apply_note_range(uint8_t lowest, uint8_t highest, bool force=false); diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc index c8cd5fe464..33315cfaa6 100644 --- a/gtk2_ardour/midi_time_axis.cc +++ b/gtk2_ardour/midi_time_axis.cc @@ -28,7 +28,9 @@ #include "pbd/error.h" #include "pbd/stl_delete.h" #include "pbd/whitespace.h" +#include "pbd/basename.h" #include "pbd/enumwriter.h" +#include "pbd/memento_command.h" #include <gtkmm2ext/gtk_ui.h> #include <gtkmm2ext/selector.h> @@ -39,40 +41,44 @@ #include "ardour/midi_playlist.h" #include "ardour/midi_diskstream.h" #include "ardour/midi_patch_manager.h" +#include "ardour/midi_source.h" #include "ardour/processor.h" #include "ardour/ladspa_plugin.h" #include "ardour/location.h" #include "ardour/playlist.h" +#include "ardour/region_factory.h" #include "ardour/session.h" #include "ardour/session_playlist.h" +#include "ardour/tempo.h" #include "ardour/utils.h" +#include "add_midi_cc_track_dialog.h" #include "ardour_ui.h" -#include "midi_time_axis.h" -#include "automation_time_axis.h" #include "automation_line.h" -#include "add_midi_cc_track_dialog.h" +#include "automation_time_axis.h" +#include "canvas-note-event.h" #include "canvas_impl.h" #include "crossfade_view.h" +#include "editor.h" #include "enums.h" +#include "ghostregion.h" #include "gui_thread.h" #include "keyboard.h" +#include "midi_scroomer.h" +#include "midi_streamview.h" +#include "midi_region_view.h" +#include "midi_time_axis.h" +#include "piano_roll_header.h" #include "playlist_selector.h" #include "plugin_selector.h" #include "plugin_ui.h" #include "point_selection.h" #include "prompter.h" -#include "public_editor.h" #include "region_view.h" #include "rgb_macros.h" #include "selection.h" #include "simplerect.h" -#include "midi_streamview.h" #include "utils.h" -#include "midi_scroomer.h" -#include "piano_roll_header.h" -#include "ghostregion.h" -#include "canvas-note-event.h" #include "ardour/midi_track.h" @@ -553,3 +559,154 @@ MidiTimeAxisView::route_active_changed () } } +void +MidiTimeAxisView::build_rec_context_menu () +{ + using namespace Menu_Helpers; + + if (!is_track()) { + return; + } + + rec_context_menu = manage (new Menu); + rec_context_menu->set_name ("ArdourContextMenu"); + + MenuList& items = rec_context_menu->items(); + + items.push_back (CheckMenuElem (_("Step Edit"), + (mem_fun (*this, &MidiTimeAxisView::toggle_step_editing)))); + _step_edit_item = dynamic_cast<CheckMenuItem*>(&items.back()); + _step_edit_item->set_active (midi_track()->step_editing()); +} + +void +MidiTimeAxisView::toggle_step_editing () +{ + if (!is_track()) { + return; + } + + bool yn = _step_edit_item->get_active(); + + if (yn) { + start_step_editing (); + } else { + stop_step_editing (); + } + + midi_track()->set_step_editing (yn); +} + +void +MidiTimeAxisView::start_step_editing () +{ + step_edit_connection = Glib::signal_timeout().connect (mem_fun (*this, &MidiTimeAxisView::check_step_edit), 20); + step_edit_insert_position = _editor.get_preferred_edit_position (); + step_edit_beat_pos = 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; + } +} + +void +MidiTimeAxisView::stop_step_editing () +{ + step_edit_connection.disconnect (); +} + +bool +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; + + 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) { + + if (step_edit_region == 0) { + cerr << "Add new region first ..\n"; + + step_edit_region = add_region (step_edit_insert_position); + RegionView* rv = view()->find_view (step_edit_region); + + if (rv) { + step_edit_region_view = dynamic_cast<MidiRegionView*>(rv); + } else { + fatal << X_("programming error: no view found for new MIDI region") << endmsg; + /*NOTREACHED*/ + } + } + + if (step_edit_region_view) { + + bool success; + Evoral::MusicalTime beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position); + + if (!success) { + continue; + } + + cerr << "will add note at " << step_edit_beat_pos << endl; + step_edit_region_view->add_note (buf[0] & 0xf, buf[1], buf[2], step_edit_beat_pos, beats); + step_edit_beat_pos += beats; + } + } + + } + + return true; /* keep checking */ +} + +boost::shared_ptr<Region> +MidiTimeAxisView::add_region (nframes64_t pos) +{ + Editor* real_editor = dynamic_cast<Editor*> (&_editor); + + real_editor->begin_reversible_command (_("create region")); + XMLNode &before = playlist()->get_state(); + + nframes64_t start = pos; + real_editor->snap_to (start, -1); + const Meter& m = _session.tempo_map().meter_at(start); + const Tempo& t = _session.tempo_map().tempo_at(start); + double length = floor (m.frames_per_bar(t, _session.frame_rate())); + + const boost::shared_ptr<MidiDiskstream> diskstream = + boost::dynamic_pointer_cast<MidiDiskstream>(view()->trackview().track()->diskstream()); + + boost::shared_ptr<Source> src = _session.create_midi_source_for_session (*diskstream.get()); + + boost::shared_ptr<Region> region = (RegionFactory::create (src, 0, (nframes_t) length, + PBD::basename_nosuffix(src->name()))); + + playlist()->add_region (region, start); + XMLNode &after = playlist()->get_state(); + _session.add_command (new MementoCommand<Playlist> (*playlist().get(), &before, &after)); + + real_editor->commit_reversible_command(); + + return region; +} diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h index acf9c32ea5..850fb90e34 100644 --- a/gtk2_ardour/midi_time_axis.h +++ b/gtk2_ardour/midi_time_axis.h @@ -67,6 +67,8 @@ class MidiTimeAxisView : public RouteTimeAxisView void set_height (uint32_t); void hide (); + boost::shared_ptr<ARDOUR::Region> add_region (nframes64_t pos); + void show_all_automation (); void show_existing_automation (); void add_cc_track (); @@ -102,6 +104,7 @@ class MidiTimeAxisView : public RouteTimeAxisView void set_note_range(MidiStreamView::VisibleNoteRange range); void route_active_changed (); + void build_rec_context_menu (); void add_insert_to_subplugin_menu (ARDOUR::Processor *); @@ -120,6 +123,19 @@ class MidiTimeAxisView : public RouteTimeAxisView MidiMultipleChannelSelector _channel_selector; Gtk::ComboBoxText _model_selector; Gtk::ComboBoxText _custom_device_mode_selector; + + Gtk::CheckMenuItem* _step_edit_item; + sigc::connection step_edit_connection; + + nframes64_t step_edit_insert_position; + Evoral::MusicalTime step_edit_beat_pos; + boost::shared_ptr<ARDOUR::Region> step_edit_region; + MidiRegionView* step_edit_region_view; + + void toggle_step_editing (); + void start_step_editing (); + void stop_step_editing (); + bool check_step_edit (); }; #endif /* __ardour_midi_time_axis_h__ */ diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index ab7fe6292a..cbd2bc5492 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -184,7 +184,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh rec_enable_button->show_all (); rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false); - rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release)); + rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release), false); controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); ARDOUR_UI::instance()->tooltips().set_tip(*rec_enable_button, _("Record")); diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index 6d21de844e..6c42de5848 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -95,6 +95,7 @@ RouteUI::init () mute_menu = 0; solo_menu = 0; sends_menu = 0; + rec_context_menu = 0; ignore_toggle = false; wait_for_release = false; route_active_menu_item = 0; @@ -498,6 +499,10 @@ RouteUI::rec_enable_press(GdkEventButton* ev) set_route_group_rec_enable (_route, !_route->record_enabled()); + } else if (Keyboard::is_context_menu_event (ev)) { + + /* do this on release */ + } else { reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this); check_rec_enable_sensitivity (); @@ -507,9 +512,31 @@ RouteUI::rec_enable_press(GdkEventButton* ev) return true; } + +void +RouteUI::show_rec_context_menu () +{ + if (!rec_context_menu) { + cerr << "build menu\n"; + build_rec_context_menu (); + } + + if (rec_context_menu) { + /* only do this if build_rec_context_menu() actually did something */ + cerr << "show menu\n"; + rec_context_menu->popup (1, gtk_get_current_event_time()); + } +} + bool -RouteUI::rec_enable_release (GdkEventButton*) +RouteUI::rec_enable_release (GdkEventButton* ev) { + cerr << "release\n"; + if (Keyboard::is_context_menu_event(ev)) { + cerr << "context\n"; + show_rec_context_menu (); + } + return true; } diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h index 1ac87a0404..17e5f77cf6 100644 --- a/gtk2_ardour/route_ui.h +++ b/gtk2_ardour/route_ui.h @@ -98,6 +98,10 @@ class RouteUI : public virtual AxisView Gtk::Menu* mute_menu; Gtk::Menu* solo_menu; Gtk::Menu* sends_menu; + Gtk::Menu* rec_context_menu; + + virtual void build_rec_context_menu () { } + void show_rec_context_menu (); XMLNode *xml_node; void ensure_xml_node (); diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index 5c5ef5c26c..0030fdc520 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -77,6 +77,10 @@ public: NoteMode note_mode() const { return _note_mode; } void set_note_mode (NoteMode m); + + bool step_editing() const { return _step_editing; } + void set_step_editing (bool yn); + MidiRingBuffer<nframes_t>& step_edit_ring_buffer() { return _step_edit_ring_buffer; } protected: XMLNode& state (bool full); @@ -93,7 +97,13 @@ private: void set_state_part_three (); MidiRingBuffer<nframes_t> _immediate_events; + MidiRingBuffer<nframes_t> _step_edit_ring_buffer; NoteMode _note_mode; + bool _step_editing; + + int no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, + bool state_changing, bool can_record, bool rec_monitors_input); + void push_midi_input_to_step_edit_ringbuffer (nframes_t nframes); }; } /* namespace ARDOUR*/ diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index 843437dab7..49e370c7b4 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -179,6 +179,8 @@ class TempoMap : public PBD::StatefulDestructible nframes_t frame_time (const BBT_Time&) const; nframes_t bbt_duration_at (nframes_t, const BBT_Time&, int dir) const; + void bbt_time_add (nframes64_t origin, BBT_Time& start, const BBT_Time& shift); + static const Tempo& default_tempo() { return _default_tempo; } static const Meter& default_meter() { return _default_meter; } diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index c2f69f0b9b..cb2d05caa6 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -45,8 +45,8 @@ class Track : public Route virtual bool can_use_mode (TrackMode /*m*/, bool& /*bounce_required*/) { return false; } sigc::signal<void> TrackModeChanged; - int no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, - bool state_changing, bool can_record, bool rec_monitors_input); + virtual int no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, + bool state_changing, bool can_record, bool rec_monitors_input); int silent_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, bool can_record, bool rec_monitors_input); diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 4c575e8cc4..267cacf787 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -36,6 +36,7 @@ #include "ardour/midi_source.h" #include "ardour/midi_track.h" #include "ardour/panner.h" +#include "ardour/port.h" #include "ardour/processor.h" #include "ardour/route_group_specialized.h" #include "ardour/session.h" @@ -50,7 +51,9 @@ using namespace PBD; MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mode) : Track (sess, name, flag, mode, DataType::MIDI) , _immediate_events(1024) // FIXME: size? + , _step_edit_ring_buffer(64) // FIXME: size? , _note_mode(Sustained) + , _step_editing (false) { use_new_diskstream (); @@ -63,7 +66,9 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo MidiTrack::MidiTrack (Session& sess, const XMLNode& node) : Track (sess, node, DataType::MIDI ) , _immediate_events(1024) // FIXME: size? + , _step_edit_ring_buffer(64) // FIXME: size? , _note_mode(Sustained) + , _step_editing (false) { _set_state(node, false); } @@ -276,6 +281,9 @@ MidiTrack::state(bool full_state) root.add_child_nocopy (_rec_enable_control->get_state()); + root.add_property ("step-editing", (_step_editing ? "yes" : "no")); + root.add_property ("note-mode", enum_2_string (_note_mode)); + return root; } @@ -449,6 +457,41 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, return 0; } +int +MidiTrack::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, + bool state_changing, bool can_record, bool rec_monitors_input) +{ + int ret = Track::no_roll (nframes, start_frame, end_frame, state_changing, can_record, rec_monitors_input); + + if (ret == 0 && _step_editing) { + push_midi_input_to_step_edit_ringbuffer (nframes); + } + + return ret; +} + +void +MidiTrack::push_midi_input_to_step_edit_ringbuffer (nframes_t nframes) +{ + PortSet& ports (_input->ports()); + + for (PortSet::iterator p = ports.begin(DataType::MIDI); p != ports.end(DataType::MIDI); ++p) { + + Buffer& b (p->get_buffer (nframes)); + const MidiBuffer* const mb = dynamic_cast<MidiBuffer*>(&b); + assert (mb); + + for (MidiBuffer::const_iterator e = mb->begin(); e != mb->end(); ++e) { + + const Evoral::MIDIEvent<nframes_t> ev(*e, false); + + /* we don't care about the time for this purpose */ + + _step_edit_ring_buffer.write (0, ev.type(), ev.size(), ev.buffer()); + } + } +} + void MidiTrack::write_out_of_band_data (BufferSet& bufs, sframes_t /*start*/, sframes_t /*end*/, nframes_t nframes) { @@ -594,3 +637,8 @@ MidiTrack::MidiControl::set_value(float val) AutomationControl::set_value(val); } +void +MidiTrack::set_step_editing (bool yn) +{ + _step_editing = yn; +} |