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)
41 /* We do not handle nested sources/regions. Caller should have tackled this */
43 if (r
->max_source_level() > 0) {
44 throw failed_constructor();
49 model
= ListStore::create (columns
);
50 view
.set_model (model
);
52 view
.signal_key_press_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_press
));
53 view
.signal_key_release_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_release
));
55 view
.append_column (_("Start"), columns
.start
);
56 view
.append_column (_("Channel"), columns
.channel
);
57 view
.append_column (_("Num"), columns
.note
);
58 view
.append_column (_("Name"), columns
.note_name
);
59 view
.append_column (_("Vel"), columns
.velocity
);
60 view
.append_column (_("Length"), columns
.length
);
61 view
.append_column (_("End"), columns
.end
);
62 view
.set_headers_visible (true);
63 view
.set_name (X_("MidiListView"));
64 view
.set_rules_hint (true);
66 for (int i
= 0; i
< 6; ++i
) {
67 CellRendererText
* renderer
= dynamic_cast<CellRendererText
*>(view
.get_column_cell_renderer (i
));
68 renderer
->property_editable() = true;
70 renderer
->signal_editing_started().connect (sigc::bind (sigc::mem_fun (*this, &MidiListEditor::editing_started
), i
));
71 renderer
->signal_editing_canceled().connect (sigc::mem_fun (*this, &MidiListEditor::editing_canceled
));
72 renderer
->signal_edited().connect (sigc::mem_fun (*this, &MidiListEditor::edited
));
76 scroller
.set_policy (POLICY_NEVER
, POLICY_AUTOMATIC
);
83 get_vbox()->pack_start (scroller
);
84 set_size_request (400, 400);
87 MidiListEditor::~MidiListEditor ()
92 MidiListEditor::key_press (GdkEventKey
* ev
)
94 bool editing
= !_current_edit
.empty();
118 MidiListEditor::key_release (GdkEventKey
* ev
)
122 switch (ev
->keyval
) {
124 delete_selected_note ();
135 MidiListEditor::delete_selected_note ()
137 Glib::RefPtr
<TreeSelection
> selection
= view
.get_selection();
138 TreeView::Selection::ListHandle_Path rows
= selection
->get_selected_rows ();
144 TreeView::Selection::ListHandle_Path::iterator i
= rows
.begin();
147 /* selection mode is single, so rows.begin() is it */
149 if ((iter
= model
->get_iter (*i
))) {
150 boost::shared_ptr
<NoteType
> note
= (*iter
)[columns
._note
];
151 cerr
<< "Would have deleted " << *note
<< endl
;
157 MidiListEditor::editing_started (CellEditable
*, const string
& path
, int colno
)
159 _current_edit
= path
;
160 cerr
<< "Now editing " << _current_edit
<< " Column " << colno
<< endl
;
164 MidiListEditor::editing_canceled ()
170 MidiListEditor::edited (const std::string
& path
, const std::string
& /* text */)
172 TreeModel::iterator iter
= model
->get_iter (path
);
174 cerr
<< "Edit at " << path
<< endl
;
180 boost::shared_ptr
<NoteType
> note
= (*iter
)[columns
._note
];
182 cerr
<< "Edited " << *note
<< endl
;
186 /* keep selected row(s), move cursor there, to allow us to continue editing */
190 MidiListEditor::redisplay_model ()
192 view
.set_model (Glib::RefPtr
<Gtk::ListStore
>(0));
197 BeatsFramesConverter
conv (_session
->tempo_map(), region
->position());
198 MidiModel::Notes notes
= region
->midi_source(0)->model()->notes();
202 for (MidiModel::Notes::iterator i
= notes
.begin(); i
!= notes
.end(); ++i
) {
203 row
= *(model
->append());
204 row
[columns
.channel
] = (*i
)->channel() + 1;
205 row
[columns
.note_name
] = Evoral::midi_note_name ((*i
)->note());
206 row
[columns
.note
] = (*i
)->note();
207 row
[columns
.velocity
] = (*i
)->velocity();
209 Timecode::BBT_Time bbt
;
212 _session
->tempo_map().bbt_time (conv
.to ((*i
)->time()), bbt
);
216 row
[columns
.start
] = ss
.str();
219 dur
= (*i
)->end_time() - (*i
)->time();
220 bbt
.beats
= floor (dur
);
221 bbt
.ticks
= (uint32_t) lrint (fmod (dur
, 1.0) * Timecode::BBT_Time::ticks_per_beat
);
223 _session
->tempo_map().bbt_duration_at (region
->position(), bbt
, 0);
227 row
[columns
.length
] = ss
.str();
229 _session
->tempo_map().bbt_time (conv
.to ((*i
)->end_time()), bbt
);
233 row
[columns
.end
] = ss
.str();
235 row
[columns
._note
] = (*i
);
239 view
.set_model (model
);