2 Copyright (C) 2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "evoral/midi_util.h"
23 #include "ardour/beats_frames_converter.h"
24 #include "ardour/midi_region.h"
25 #include "ardour/session.h"
26 #include "ardour/tempo.h"
28 #include "midi_list_editor.h"
35 using namespace ARDOUR
;
37 MidiListEditor::MidiListEditor (Session
* s
, boost::shared_ptr
<MidiRegion
> r
)
38 : ArdourDialog (r
->name(), false, false)
43 model
= ListStore::create (columns
);
44 view
.set_model (model
);
46 view
.signal_key_press_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_press
));
47 view
.signal_key_release_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_release
));
49 view
.append_column (_("Start"), columns
.start
);
50 view
.append_column (_("Channel"), columns
.channel
);
51 view
.append_column (_("Num"), columns
.note
);
52 view
.append_column (_("Name"), columns
.note_name
);
53 view
.append_column (_("Vel"), columns
.velocity
);
54 view
.append_column (_("Length"), columns
.length
);
55 view
.append_column (_("End"), columns
.end
);
56 view
.set_headers_visible (true);
57 view
.set_name (X_("MidiListView"));
58 view
.set_rules_hint (true);
60 for (int i
= 0; i
< 6; ++i
) {
61 CellRendererText
* renderer
= dynamic_cast<CellRendererText
*>(view
.get_column_cell_renderer (i
));
62 renderer
->property_editable() = true;
64 renderer
->signal_editing_started().connect (sigc::bind (sigc::mem_fun (*this, &MidiListEditor::editing_started
), i
));
65 renderer
->signal_editing_canceled().connect (sigc::mem_fun (*this, &MidiListEditor::editing_canceled
));
66 renderer
->signal_edited().connect (sigc::mem_fun (*this, &MidiListEditor::edited
));
70 scroller
.set_policy (POLICY_NEVER
, POLICY_AUTOMATIC
);
77 get_vbox()->pack_start (scroller
);
78 set_size_request (400, 400);
81 MidiListEditor::~MidiListEditor ()
86 MidiListEditor::key_press (GdkEventKey
* ev
)
88 bool editing
= !_current_edit
.empty();
112 MidiListEditor::key_release (GdkEventKey
* ev
)
116 switch (ev
->keyval
) {
118 delete_selected_note ();
129 MidiListEditor::delete_selected_note ()
131 Glib::RefPtr
<TreeSelection
> selection
= view
.get_selection();
132 TreeView::Selection::ListHandle_Path rows
= selection
->get_selected_rows ();
138 TreeView::Selection::ListHandle_Path::iterator i
= rows
.begin();
141 /* selection mode is single, so rows.begin() is it */
143 if ((iter
= model
->get_iter (*i
))) {
144 boost::shared_ptr
<NoteType
> note
= (*iter
)[columns
._note
];
145 cerr
<< "Would have deleted " << *note
<< endl
;
151 MidiListEditor::editing_started (CellEditable
*, const ustring
& path
, int colno
)
153 _current_edit
= path
;
154 cerr
<< "Now editing " << _current_edit
<< " Column " << colno
<< endl
;
158 MidiListEditor::editing_canceled ()
164 MidiListEditor::edited (const Glib::ustring
& path
, const Glib::ustring
& /* text */)
166 TreeModel::iterator iter
= model
->get_iter (path
);
168 cerr
<< "Edit at " << path
<< endl
;
174 boost::shared_ptr
<NoteType
> note
= (*iter
)[columns
._note
];
176 cerr
<< "Edited " << *note
<< endl
;
180 /* keep selected row(s), move cursor there, to allow us to continue editing */
184 MidiListEditor::redisplay_model ()
186 view
.set_model (Glib::RefPtr
<Gtk::ListStore
>(0));
191 BeatsFramesConverter
conv (_session
->tempo_map(), region
->position());
192 MidiModel::Notes notes
= region
->midi_source(0)->model()->notes();
196 for (MidiModel::Notes::iterator i
= notes
.begin(); i
!= notes
.end(); ++i
) {
197 row
= *(model
->append());
198 row
[columns
.channel
] = (*i
)->channel() + 1;
199 row
[columns
.note_name
] = Evoral::midi_note_name ((*i
)->note());
200 row
[columns
.note
] = (*i
)->note();
201 row
[columns
.velocity
] = (*i
)->velocity();
206 _session
->tempo_map().bbt_time (conv
.to ((*i
)->time()), bbt
);
210 row
[columns
.start
] = ss
.str();
213 dur
= (*i
)->end_time() - (*i
)->time();
214 bbt
.beats
= floor (dur
);
215 bbt
.ticks
= (uint32_t) lrint (fmod (dur
, 1.0) * Meter::ticks_per_beat
);
217 _session
->tempo_map().bbt_duration_at (region
->position(), bbt
, 0);
221 row
[columns
.length
] = ss
.str();
223 _session
->tempo_map().bbt_time (conv
.to ((*i
)->end_time()), bbt
);
227 row
[columns
.end
] = ss
.str();
229 row
[columns
._note
] = (*i
);
233 view
.set_model (model
);