summaryrefslogtreecommitdiff
path: root/gtk2_ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2009-09-03 12:39:50 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2009-09-03 12:39:50 +0000
commitb0b584c2a595bfdf6bb4b980bd8d8fc7f3546fc5 (patch)
tree0bbe7220f24b7e7cefadc546d19c409ea357820f /gtk2_ardour
parentc8932292e19f31cab856096c94788bd3f6c5b5fc (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
Diffstat (limited to 'gtk2_ardour')
-rw-r--r--gtk2_ardour/editor_drag.cc31
-rw-r--r--gtk2_ardour/export_file_notebook.cc3
-rw-r--r--gtk2_ardour/midi_list_editor.cc57
-rw-r--r--gtk2_ardour/midi_list_editor.h14
-rw-r--r--gtk2_ardour/midi_region_view.cc27
-rw-r--r--gtk2_ardour/midi_region_view.h3
-rw-r--r--gtk2_ardour/midi_time_axis.cc175
-rw-r--r--gtk2_ardour/midi_time_axis.h16
-rw-r--r--gtk2_ardour/route_time_axis.cc2
-rw-r--r--gtk2_ardour/route_ui.cc29
-rw-r--r--gtk2_ardour/route_ui.h4
11 files changed, 305 insertions, 56 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 ();