the basics of step editing, more details to follow
git-svn-id: svn://localhost/ardour2/branches/3.0@5629 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
c8932292e1
commit
b0b584c2a5
|
@ -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;
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 (_("Channel"), columns.channel);
|
||||
view.append_column (_("Note"), 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 (_("Channel"), columns.channel);
|
||||
view.append_column (_("Num"), columns.note);
|
||||
view.append_column (_("Name"), columns.note_name);
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
@ -2235,6 +2236,30 @@ MidiRegionView::paste (nframes64_t pos, float times, const MidiCutBuffer& mcb)
|
|||
apply_command ();
|
||||
}
|
||||
|
||||
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 ()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 "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 "ardour_ui.h"
|
||||
#include "automation_line.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;
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
bool
|
||||
RouteUI::rec_enable_release (GdkEventButton*)
|
||||
|
||||
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* ev)
|
||||
{
|
||||
cerr << "release\n";
|
||||
if (Keyboard::is_context_menu_event(ev)) {
|
||||
cerr << "context\n";
|
||||
show_rec_context_menu ();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user