mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 14:54:56 +01:00
start to provide real functionality in MIDI list editor. far from finished, but then, have *you* read the Logic manual?
git-svn-id: svn://localhost/ardour2/branches/3.0@11415 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
a09a71d674
commit
e39e6196c6
3 changed files with 281 additions and 46 deletions
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <gtkmm/cellrenderercombo.h>
|
||||||
|
|
||||||
#include "evoral/midi_util.h"
|
#include "evoral/midi_util.h"
|
||||||
#include "evoral/Note.hpp"
|
#include "evoral/Note.hpp"
|
||||||
|
|
||||||
|
|
@ -32,6 +34,7 @@
|
||||||
#include "gtkmm2ext/keyboard.h"
|
#include "gtkmm2ext/keyboard.h"
|
||||||
|
|
||||||
#include "midi_list_editor.h"
|
#include "midi_list_editor.h"
|
||||||
|
#include "note_player.h"
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
|
|
@ -39,10 +42,12 @@ using namespace std;
|
||||||
using namespace Gtk;
|
using namespace Gtk;
|
||||||
using namespace Glib;
|
using namespace Glib;
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
|
using Timecode::BBT_Time;
|
||||||
|
|
||||||
MidiListEditor::MidiListEditor (Session* s, boost::shared_ptr<MidiRegion> r)
|
MidiListEditor::MidiListEditor (Session* s, boost::shared_ptr<MidiRegion> r, boost::shared_ptr<MidiTrack> tr)
|
||||||
: ArdourWindow (r->name())
|
: ArdourWindow (r->name())
|
||||||
, region (r)
|
, region (r)
|
||||||
|
, track (tr)
|
||||||
{
|
{
|
||||||
/* We do not handle nested sources/regions. Caller should have tackled this */
|
/* We do not handle nested sources/regions. Caller should have tackled this */
|
||||||
|
|
||||||
|
|
@ -52,25 +57,79 @@ MidiListEditor::MidiListEditor (Session* s, boost::shared_ptr<MidiRegion> r)
|
||||||
|
|
||||||
set_session (s);
|
set_session (s);
|
||||||
|
|
||||||
|
edit_column = -1;
|
||||||
|
editing_renderer = 0;
|
||||||
|
|
||||||
model = ListStore::create (columns);
|
model = ListStore::create (columns);
|
||||||
view.set_model (model);
|
view.set_model (model);
|
||||||
|
|
||||||
view.signal_key_press_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_press));
|
note_length_model = ListStore::create (note_length_columns);
|
||||||
view.signal_key_release_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_release));
|
TreeModel::Row row;
|
||||||
|
row = *(note_length_model->append());
|
||||||
|
row[note_length_columns.ticks] = BBT_Time::ticks_per_beat;
|
||||||
|
row[note_length_columns.name] = _("Whole");
|
||||||
|
|
||||||
|
row = *(note_length_model->append());
|
||||||
|
row[note_length_columns.ticks] = BBT_Time::ticks_per_beat/2;
|
||||||
|
row[note_length_columns.name] = _("Half");
|
||||||
|
|
||||||
|
row = *(note_length_model->append());
|
||||||
|
row[note_length_columns.ticks] = BBT_Time::ticks_per_beat/3;
|
||||||
|
row[note_length_columns.name] = _("Triplet");
|
||||||
|
|
||||||
|
row = *(note_length_model->append());
|
||||||
|
row[note_length_columns.ticks] = BBT_Time::ticks_per_beat/4;
|
||||||
|
row[note_length_columns.name] = _("Quarter");
|
||||||
|
|
||||||
|
row = *(note_length_model->append());
|
||||||
|
row[note_length_columns.ticks] = BBT_Time::ticks_per_beat/8;
|
||||||
|
row[note_length_columns.name] = _("Eighth");
|
||||||
|
|
||||||
|
row = *(note_length_model->append());
|
||||||
|
row[note_length_columns.ticks] = BBT_Time::ticks_per_beat;
|
||||||
|
row[note_length_columns.name] = _("Sixteenth");
|
||||||
|
|
||||||
|
row = *(note_length_model->append());
|
||||||
|
row[note_length_columns.ticks] = BBT_Time::ticks_per_beat/32;
|
||||||
|
row[note_length_columns.name] = _("Thirty-second");
|
||||||
|
|
||||||
|
row = *(note_length_model->append());
|
||||||
|
row[note_length_columns.ticks] = BBT_Time::ticks_per_beat/64;
|
||||||
|
row[note_length_columns.name] = _("Sixty-fourth");
|
||||||
|
|
||||||
|
view.signal_key_press_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_press), false);
|
||||||
|
view.signal_key_release_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_release), false);
|
||||||
|
|
||||||
view.append_column (_("Start"), columns.start);
|
view.append_column (_("Start"), columns.start);
|
||||||
view.append_column (_("Channel"), columns.channel);
|
view.append_column (_("Channel"), columns.channel);
|
||||||
view.append_column (_("Num"), columns.note);
|
view.append_column (_("Num"), columns.note);
|
||||||
view.append_column (_("Name"), columns.note_name);
|
view.append_column (_("Name"), columns.note_name);
|
||||||
view.append_column (_("Vel"), columns.velocity);
|
view.append_column (_("Vel"), columns.velocity);
|
||||||
view.append_column (_("Length"), columns.length);
|
|
||||||
|
/* use a combo renderer for length, so that we can offer a selection
|
||||||
|
of pre-defined note lengths. we still allow edited values with
|
||||||
|
arbitrary length (in ticks).
|
||||||
|
*/
|
||||||
|
|
||||||
|
Gtk::TreeViewColumn* lenCol = Gtk::manage (new Gtk::TreeViewColumn (_("Length")));
|
||||||
|
Gtk::CellRendererCombo* comboCell = Gtk::manage(new Gtk::CellRendererCombo);
|
||||||
|
lenCol->pack_start(*comboCell);
|
||||||
|
lenCol->add_attribute (comboCell->property_text(), columns.length);
|
||||||
|
|
||||||
|
comboCell->property_model() = note_length_model;
|
||||||
|
comboCell->property_text_column() = 1;
|
||||||
|
comboCell->property_has_entry() = false;
|
||||||
|
|
||||||
|
view.append_column (*lenCol);
|
||||||
view.append_column (_("End"), columns.end);
|
view.append_column (_("End"), columns.end);
|
||||||
view.set_headers_visible (true);
|
view.set_headers_visible (true);
|
||||||
view.set_rules_hint (true);
|
view.set_rules_hint (true);
|
||||||
view.get_selection()->set_mode (SELECTION_MULTIPLE);
|
view.get_selection()->set_mode (SELECTION_MULTIPLE);
|
||||||
|
view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &MidiListEditor::selection_changed));
|
||||||
|
|
||||||
for (int i = 0; i < 6; ++i) {
|
for (int i = 0; i < 7; ++i) {
|
||||||
CellRendererText* renderer = dynamic_cast<CellRendererText*>(view.get_column_cell_renderer (i));
|
CellRendererText* renderer = dynamic_cast<CellRendererText*>(view.get_column_cell_renderer (i));
|
||||||
|
|
||||||
renderer->property_editable() = true;
|
renderer->property_editable() = true;
|
||||||
|
|
||||||
renderer->signal_editing_started().connect (sigc::bind (sigc::mem_fun (*this, &MidiListEditor::editing_started), i));
|
renderer->signal_editing_started().connect (sigc::bind (sigc::mem_fun (*this, &MidiListEditor::editing_started), i));
|
||||||
|
|
@ -88,8 +147,13 @@ MidiListEditor::MidiListEditor (Session* s, boost::shared_ptr<MidiRegion> r)
|
||||||
|
|
||||||
view.show ();
|
view.show ();
|
||||||
scroller.show ();
|
scroller.show ();
|
||||||
|
buttons.show ();
|
||||||
|
vbox.show ();
|
||||||
|
|
||||||
add (scroller);
|
vbox.pack_start (buttons, false, false);
|
||||||
|
vbox.pack_start (scroller, true, true);
|
||||||
|
|
||||||
|
add (vbox);
|
||||||
set_size_request (-1, 400);
|
set_size_request (-1, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,25 +164,50 @@ MidiListEditor::~MidiListEditor ()
|
||||||
bool
|
bool
|
||||||
MidiListEditor::key_press (GdkEventKey* ev)
|
MidiListEditor::key_press (GdkEventKey* ev)
|
||||||
{
|
{
|
||||||
bool editing = !_current_edit.empty();
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
TreeModel::Path path;
|
||||||
|
TreeViewColumn* col;
|
||||||
|
|
||||||
if (editing) {
|
|
||||||
switch (ev->keyval) {
|
switch (ev->keyval) {
|
||||||
case GDK_Tab:
|
case GDK_Tab:
|
||||||
break;
|
if (edit_column > 0) {
|
||||||
case GDK_Right:
|
if (edit_column >= 6) {
|
||||||
break;
|
edit_column = 0;
|
||||||
case GDK_Left:
|
edit_path.next();
|
||||||
break;
|
} else {
|
||||||
case GDK_Up:
|
edit_column++;
|
||||||
break;
|
}
|
||||||
case GDK_Down:
|
col = view.get_column (edit_column);
|
||||||
break;
|
path = edit_path;
|
||||||
case GDK_Escape:
|
view.set_cursor (path, *col, true);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GDK_Up:
|
||||||
|
if (edit_column > 0) {
|
||||||
|
edit_path.prev ();
|
||||||
|
col = view.get_column (edit_column);
|
||||||
|
path = edit_path;
|
||||||
|
view.set_cursor (path, *col, true);
|
||||||
|
ret = true;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GDK_Down:
|
||||||
|
if (edit_column > 0) {
|
||||||
|
edit_path.next ();
|
||||||
|
col = view.get_column (edit_column);
|
||||||
|
path = edit_path;
|
||||||
|
view.set_cursor (path, *col, true);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GDK_Escape:
|
||||||
|
stop_editing (true);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -128,22 +217,53 @@ bool
|
||||||
MidiListEditor::key_release (GdkEventKey* ev)
|
MidiListEditor::key_release (GdkEventKey* ev)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
TreeModel::Path path;
|
||||||
|
TreeViewColumn* col;
|
||||||
|
TreeModel::iterator iter;
|
||||||
|
TreeModel::Row row;
|
||||||
|
MidiModel::NoteDiffCommand* cmd;
|
||||||
|
boost::shared_ptr<MidiModel> m (region->midi_source(0)->model());
|
||||||
|
boost::shared_ptr<NoteType> note;
|
||||||
|
boost::shared_ptr<NoteType> copy;
|
||||||
|
|
||||||
switch (ev->keyval) {
|
switch (ev->keyval) {
|
||||||
|
case GDK_Insert:
|
||||||
|
/* add a new note to the model, based on the note at the cursor
|
||||||
|
* pos
|
||||||
|
*/
|
||||||
|
view.get_cursor (path, col);
|
||||||
|
iter = model->get_iter (path);
|
||||||
|
cmd = m->new_note_diff_command (_("insert new note"));
|
||||||
|
note = (*iter)[columns._note];
|
||||||
|
copy.reset (new NoteType (*note.get()));
|
||||||
|
cmd->add (copy);
|
||||||
|
m->apply_command (*_session, cmd);
|
||||||
|
/* model has been redisplayed by now */
|
||||||
|
path.next ();
|
||||||
|
/* select, start editing column 2 (note) */
|
||||||
|
col = view.get_column (2);
|
||||||
|
view.set_cursor (path, *col, true);
|
||||||
|
break;
|
||||||
|
|
||||||
case GDK_Delete:
|
case GDK_Delete:
|
||||||
case GDK_BackSpace:
|
case GDK_BackSpace:
|
||||||
|
if (edit_column < 0) {
|
||||||
delete_selected_note ();
|
delete_selected_note ();
|
||||||
|
}
|
||||||
ret = true;
|
ret = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GDK_z:
|
case GDK_z:
|
||||||
if (_session && Gtkmm2ext::Keyboard::modifier_state_contains (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
|
if (_session && Gtkmm2ext::Keyboard::modifier_state_contains (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
|
||||||
_session->undo (1);
|
_session->undo (1);
|
||||||
|
ret = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GDK_r:
|
case GDK_r:
|
||||||
if (_session && Gtkmm2ext::Keyboard::modifier_state_contains (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
|
if (_session && Gtkmm2ext::Keyboard::modifier_state_contains (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
|
||||||
_session->redo (1);
|
_session->redo (1);
|
||||||
|
ret = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -186,37 +306,109 @@ MidiListEditor::delete_selected_note ()
|
||||||
m->apply_command (*_session, cmd);
|
m->apply_command (*_session, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiListEditor::stop_editing (bool cancelled)
|
||||||
|
{
|
||||||
|
if (editing_renderer) {
|
||||||
|
editing_renderer->stop_editing (cancelled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiListEditor::editing_started (CellEditable*, const string& path, int colno)
|
MidiListEditor::editing_started (CellEditable*, const string& path, int colno)
|
||||||
{
|
{
|
||||||
_current_edit = path;
|
cerr << "start editing at [" << path << "] col " << colno << endl;
|
||||||
cerr << "Now editing " << _current_edit << " Column " << colno << endl;
|
edit_path = TreePath (path);
|
||||||
|
edit_column = colno;
|
||||||
|
editing_renderer = dynamic_cast<CellRendererText*>(view.get_column_cell_renderer (colno));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiListEditor::editing_canceled ()
|
MidiListEditor::editing_canceled ()
|
||||||
{
|
{
|
||||||
_current_edit = "";
|
cerr << "editing cancelled with edit_column = " << edit_column << " path \"" << edit_path.to_string() << "\"\n";
|
||||||
|
edit_path.clear ();
|
||||||
|
edit_column = -1;
|
||||||
|
editing_renderer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiListEditor::edited (const std::string& path, const std::string& /* text */)
|
MidiListEditor::edited (const std::string& path, const std::string& text)
|
||||||
{
|
{
|
||||||
TreeModel::iterator iter = model->get_iter (path);
|
TreeModel::iterator iter = model->get_iter (path);
|
||||||
|
|
||||||
cerr << "Edit at " << path << endl;
|
if (!iter || text.empty()) {
|
||||||
|
|
||||||
if (!iter) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cerr << "Edited " << path << " col " << edit_column << " to \"" << text << "\"\n";
|
||||||
|
|
||||||
boost::shared_ptr<NoteType> note = (*iter)[columns._note];
|
boost::shared_ptr<NoteType> note = (*iter)[columns._note];
|
||||||
|
boost::shared_ptr<MidiModel> m (region->midi_source(0)->model());
|
||||||
|
MidiModel::NoteDiffCommand* cmd;
|
||||||
|
|
||||||
cerr << "Edited " << *note << endl;
|
cmd = m->new_note_diff_command (_("insert new note"));
|
||||||
|
|
||||||
redisplay_model ();
|
double fval;
|
||||||
|
int ival;
|
||||||
|
bool apply = false;
|
||||||
|
|
||||||
|
switch (edit_column) {
|
||||||
|
case 0: // start
|
||||||
|
break;
|
||||||
|
case 1: // channel
|
||||||
|
// correct ival for zero-based counting after scan
|
||||||
|
if (sscanf (text.c_str(), "%d", &ival) == 1 && --ival != note->note()) {
|
||||||
|
cmd->change (note, MidiModel::NoteDiffCommand::NoteNumber, (uint8_t) ival);
|
||||||
|
apply = true;
|
||||||
|
cerr << "channel differs " << (int) ival << " vs. " << (int) note->channel() << endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: // note
|
||||||
|
if (sscanf (text.c_str(), "%d", &ival) == 1 && ival != note->note()) {
|
||||||
|
cmd->change (note, MidiModel::NoteDiffCommand::NoteNumber, (uint8_t) ival);
|
||||||
|
apply = true;
|
||||||
|
cerr << "note number differs " << (int) ival << " vs. " << (int) note->note() << endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3: // name
|
||||||
|
break;
|
||||||
|
case 4: // velocity
|
||||||
|
if (sscanf (text.c_str(), "%d", &ival) == 1 && ival != note->velocity()) {
|
||||||
|
cmd->change (note, MidiModel::NoteDiffCommand::Velocity, (uint8_t) ival);
|
||||||
|
apply = true;
|
||||||
|
cerr << "velocity differs " << (int) ival << " vs. " << (int) note->velocity() << endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5: // length
|
||||||
|
if (sscanf (text.c_str(), "%d", &ival) == 1) {
|
||||||
|
fval = (double) ival / Timecode::BBT_Time::ticks_per_beat;
|
||||||
|
|
||||||
|
if (fval != note->length()) {
|
||||||
|
cmd->change (note, MidiModel::NoteDiffCommand::Length, fval);
|
||||||
|
apply = true;
|
||||||
|
cerr << "length differs: " << fval << " vs. " << note->length() << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6: // end
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apply) {
|
||||||
|
cerr << "Apply change\n";
|
||||||
|
m->apply_command (*_session, cmd);
|
||||||
|
} else {
|
||||||
|
cerr << "No change\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* model has been redisplayed by now */
|
||||||
/* keep selected row(s), move cursor there, to allow us to continue editing */
|
/* keep selected row(s), move cursor there, to allow us to continue editing */
|
||||||
|
|
||||||
|
TreeViewColumn* col = view.get_column (edit_column);
|
||||||
|
view.set_cursor (edit_path, *col, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -253,11 +445,7 @@ MidiListEditor::redisplay_model ()
|
||||||
bbt.beats = floor (dur);
|
bbt.beats = floor (dur);
|
||||||
bbt.ticks = (uint32_t) lrint (fmod (dur, 1.0) * Timecode::BBT_Time::ticks_per_beat);
|
bbt.ticks = (uint32_t) lrint (fmod (dur, 1.0) * Timecode::BBT_Time::ticks_per_beat);
|
||||||
|
|
||||||
_session->tempo_map().bbt_duration_at (region->position(), bbt, 0);
|
row[columns.length] = lrint ((*i)->length() * Timecode::BBT_Time::ticks_per_beat);
|
||||||
|
|
||||||
ss.str ("");
|
|
||||||
ss << bbt;
|
|
||||||
row[columns.length] = ss.str();
|
|
||||||
|
|
||||||
_session->tempo_map().bbt_time (conv.to ((*i)->end_time()), bbt);
|
_session->tempo_map().bbt_time (conv.to ((*i)->end_time()), bbt);
|
||||||
|
|
||||||
|
|
@ -271,3 +459,27 @@ MidiListEditor::redisplay_model ()
|
||||||
|
|
||||||
view.set_model (model);
|
view.set_model (model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiListEditor::selection_changed ()
|
||||||
|
{
|
||||||
|
if (!Config->get_sound_midi_notes()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeModel::Path path;
|
||||||
|
TreeModel::iterator iter;
|
||||||
|
boost::shared_ptr<NoteType> note;
|
||||||
|
TreeView::Selection::ListHandle_Path rows = view.get_selection()->get_selected_rows ();
|
||||||
|
|
||||||
|
NotePlayer* player = new NotePlayer (track);
|
||||||
|
|
||||||
|
for (TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); i != rows.end(); ++i) {
|
||||||
|
if (iter = model->get_iter (*i)) {
|
||||||
|
note = (*iter)[columns._note];
|
||||||
|
player->add (note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
player->play ();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@
|
||||||
#define __ardour_gtk2_midi_list_editor_h_
|
#define __ardour_gtk2_midi_list_editor_h_
|
||||||
|
|
||||||
#include <gtkmm/treeview.h>
|
#include <gtkmm/treeview.h>
|
||||||
|
#include <gtkmm/table.h>
|
||||||
|
#include <gtkmm/box.h>
|
||||||
#include <gtkmm/liststore.h>
|
#include <gtkmm/liststore.h>
|
||||||
#include <gtkmm/scrolledwindow.h>
|
#include <gtkmm/scrolledwindow.h>
|
||||||
|
|
||||||
|
|
@ -36,6 +38,7 @@ namespace Evoral {
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
class MidiRegion;
|
class MidiRegion;
|
||||||
class MidiModel;
|
class MidiModel;
|
||||||
|
class MidiTrack;
|
||||||
class Session;
|
class Session;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -44,7 +47,8 @@ class MidiListEditor : public ArdourWindow
|
||||||
public:
|
public:
|
||||||
typedef Evoral::Note<Evoral::MusicalTime> NoteType;
|
typedef Evoral::Note<Evoral::MusicalTime> NoteType;
|
||||||
|
|
||||||
MidiListEditor(ARDOUR::Session*, boost::shared_ptr<ARDOUR::MidiRegion>);
|
MidiListEditor(ARDOUR::Session*, boost::shared_ptr<ARDOUR::MidiRegion>,
|
||||||
|
boost::shared_ptr<ARDOUR::MidiTrack>);
|
||||||
~MidiListEditor();
|
~MidiListEditor();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -64,18 +68,35 @@ class MidiListEditor : public ArdourWindow
|
||||||
Gtk::TreeModelColumn<std::string> note_name;
|
Gtk::TreeModelColumn<std::string> note_name;
|
||||||
Gtk::TreeModelColumn<uint8_t> velocity;
|
Gtk::TreeModelColumn<uint8_t> velocity;
|
||||||
Gtk::TreeModelColumn<std::string> start;
|
Gtk::TreeModelColumn<std::string> start;
|
||||||
Gtk::TreeModelColumn<std::string> length;
|
Gtk::TreeModelColumn<int> length;
|
||||||
Gtk::TreeModelColumn<std::string> end;
|
Gtk::TreeModelColumn<std::string> end;
|
||||||
Gtk::TreeModelColumn<boost::shared_ptr<NoteType> > _note;
|
Gtk::TreeModelColumn<boost::shared_ptr<NoteType> > _note;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NoteLengthColumns : public Gtk::TreeModel::ColumnRecord {
|
||||||
|
NoteLengthColumns() {
|
||||||
|
add (ticks);
|
||||||
|
add (name);
|
||||||
|
}
|
||||||
|
Gtk::TreeModelColumn<int> ticks;
|
||||||
|
Gtk::TreeModelColumn<std::string> name;
|
||||||
|
};
|
||||||
|
|
||||||
MidiListModelColumns columns;
|
MidiListModelColumns columns;
|
||||||
Glib::RefPtr<Gtk::ListStore> model;
|
Glib::RefPtr<Gtk::ListStore> model;
|
||||||
|
NoteLengthColumns note_length_columns;
|
||||||
|
Glib::RefPtr<Gtk::ListStore> note_length_model;
|
||||||
Gtk::TreeView view;
|
Gtk::TreeView view;
|
||||||
Gtk::ScrolledWindow scroller;
|
Gtk::ScrolledWindow scroller;
|
||||||
std::string _current_edit;
|
Gtk::TreeModel::Path edit_path;
|
||||||
|
int edit_column;
|
||||||
|
Gtk::CellRendererText* editing_renderer;
|
||||||
|
Gtk::Table buttons;
|
||||||
|
Gtk::VBox vbox;
|
||||||
|
Gtk::ToggleButton additional_info_button;
|
||||||
|
|
||||||
boost::shared_ptr<ARDOUR::MidiRegion> region;
|
boost::shared_ptr<ARDOUR::MidiRegion> region;
|
||||||
|
boost::shared_ptr<ARDOUR::MidiTrack> track;
|
||||||
|
|
||||||
/** connection used to connect to model's ContentChanged signal */
|
/** connection used to connect to model's ContentChanged signal */
|
||||||
PBD::ScopedConnection content_connection;
|
PBD::ScopedConnection content_connection;
|
||||||
|
|
@ -83,6 +104,7 @@ class MidiListEditor : public ArdourWindow
|
||||||
void edited (const std::string&, const std::string&);
|
void edited (const std::string&, const std::string&);
|
||||||
void editing_started (Gtk::CellEditable*, const std::string& path, int);
|
void editing_started (Gtk::CellEditable*, const std::string& path, int);
|
||||||
void editing_canceled ();
|
void editing_canceled ();
|
||||||
|
void stop_editing (bool cancelled = false);
|
||||||
|
|
||||||
void redisplay_model ();
|
void redisplay_model ();
|
||||||
|
|
||||||
|
|
@ -90,6 +112,7 @@ class MidiListEditor : public ArdourWindow
|
||||||
bool key_release (GdkEventKey* ev);
|
bool key_release (GdkEventKey* ev);
|
||||||
|
|
||||||
void delete_selected_note ();
|
void delete_selected_note ();
|
||||||
|
void selection_changed ();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __ardour_gtk2_midi_list_editor_h_ */
|
#endif /* __ardour_gtk2_midi_list_editor_h_ */
|
||||||
|
|
|
||||||
|
|
@ -811,7 +811,7 @@ void
|
||||||
MidiRegionView::show_list_editor ()
|
MidiRegionView::show_list_editor ()
|
||||||
{
|
{
|
||||||
if (!_list_editor) {
|
if (!_list_editor) {
|
||||||
_list_editor = new MidiListEditor (trackview.session(), midi_region());
|
_list_editor = new MidiListEditor (trackview.session(), midi_region(), midi_view()->midi_track());
|
||||||
}
|
}
|
||||||
_list_editor->present ();
|
_list_editor->present ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue