13
0

first somewhat version of show-clip-capture MIDI notes as they arrive

This commit is contained in:
Paul Davis 2024-10-13 09:03:44 -06:00
parent bd0b5495c6
commit d7e85de7c2
7 changed files with 176 additions and 80 deletions

View File

@ -78,6 +78,8 @@ MidiCueEditor::MidiCueEditor()
_toolbox.pack_start (viewport(), true, true);
view = new MidiCueView (nullptr, 0, *data_group, *this, *bg, 0xff0000ff);
_verbose_cursor = new VerboseCursor (*this);
// _playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event, X_("playhead"));
@ -329,12 +331,9 @@ MidiCueEditor::canvas_allocate (Gtk::Allocation alloc)
_visible_canvas_width = alloc.get_width();
_visible_canvas_height = alloc.get_height();
if (view) {
double timebars = n_timebars * timebar_height;
view->set_height (alloc.get_height() - timebars);
} else {
bg->set_size (alloc.get_width(), alloc.get_height());
}
double timebars = n_timebars * timebar_height;
view->set_height (alloc.get_height() - timebars);
bg->set_size (alloc.get_width(), alloc.get_height());
}
timepos_t
@ -444,26 +443,42 @@ MidiCueEditor::data_captured ()
void
MidiCueEditor::set_box (std::shared_ptr<ARDOUR::TriggerBox> b)
{
capture_connection.disconnect ();
capture_connections.drop_connections ();
if (b) {
std::cerr << "Bix set to " << b->order() << std::endl;
b->Captured.connect (capture_connection, invalidator (*this), boost::bind (&MidiCueEditor::data_captured, this), gui_context());
b->Captured.connect (capture_connections, invalidator (*this), boost::bind (&MidiCueEditor::data_captured, this), gui_context());
/* Don't bind a shared_ptr<TriggerBox> within the lambda */
TriggerBox* tb (b.get());
b->RecEnableChanged.connect (capture_connections, invalidator (*this), [&, tb]() { rec_enable_change (tb); }, gui_context());
}
}
void
MidiCueEditor::set_region (std::shared_ptr<ARDOUR::MidiTrack> t, uint32_t slot_index, std::shared_ptr<ARDOUR::MidiRegion> r)
MidiCueEditor::rec_enable_change (ARDOUR::TriggerBox* b)
{
delete view;
view = nullptr;
if (b->record_enabled()) {
view->begin_write();
} else {
view->end_write ();
}
}
if (!t || !r) {
void
MidiCueEditor::set_track (std::shared_ptr<ARDOUR::MidiTrack> t)
{
view->set_track (t);
}
void
MidiCueEditor::set_region (std::shared_ptr<ARDOUR::MidiRegion> r)
{
if (!r) {
bg->set_view (nullptr);
prh->set_view (nullptr);
#warning paul unset view model
return;
}
view = new MidiCueView (t, r, slot_index, *data_group, *this, *bg, 0xff0000ff);
view->set_region (r);
bg->set_view (view);
prh->set_view (view);

View File

@ -72,8 +72,9 @@ class MidiCueEditor : public CueEditor
int32_t get_grid_beat_divisions (Editing::GridType gt) const { return 1; }
int32_t get_grid_music_divisions (Editing::GridType gt, uint32_t event_state) const { return 1; }
void set_region (std::shared_ptr<ARDOUR::MidiTrack>, uint32_t slot_index, std::shared_ptr<ARDOUR::MidiRegion>);
void set_region (std::shared_ptr<ARDOUR::MidiRegion>);
void set_box (std::shared_ptr<ARDOUR::TriggerBox>);
void set_track (std::shared_ptr<ARDOUR::MidiTrack>);
ArdourCanvas::ScrollGroup* get_hscroll_group () const { return h_scroll_group; }
ArdourCanvas::ScrollGroup* get_cursor_scroll_group () const { return cursor_scroll_group; }
@ -205,8 +206,9 @@ class MidiCueEditor : public CueEditor
void visual_changer (const VisualChange&);
void bindings_changed ();
void rec_enable_change (ARDOUR::TriggerBox*);
void data_captured ();
PBD::ScopedConnection capture_connection;
PBD::ScopedConnectionList capture_connections;
};

View File

@ -42,7 +42,6 @@
using namespace Gtkmm2ext;
MidiCueView::MidiCueView (std::shared_ptr<ARDOUR::MidiTrack> mt,
std::shared_ptr<ARDOUR::MidiRegion> region,
uint32_t slot_index,
ArdourCanvas::Item& parent,
EditingContext& ec,
@ -83,7 +82,6 @@ MidiCueView::MidiCueView (std::shared_ptr<ARDOUR::MidiTrack> mt,
}
set_extensible (true);
set_region (region);
Evoral::Parameter fully_qualified_param (ARDOUR::MidiCCAutomation, 0, MIDI_CTL_MSB_MODWHEEL);
show_automation (fully_qualified_param);
@ -242,6 +240,10 @@ MidiCueView::show_automation (Evoral::Parameter const & param)
{
using namespace ARDOUR;
if (!_midi_region) {
return;
}
if (param.type() == NullAutomation) {
return;
}

View File

@ -33,7 +33,6 @@ class MidiCueView : public MidiView
{
public:
MidiCueView (std::shared_ptr<ARDOUR::MidiTrack> mt,
std::shared_ptr<ARDOUR::MidiRegion> region,
uint32_t slot_index,
ArdourCanvas::Item& parent,
EditingContext& ec,

View File

@ -141,7 +141,8 @@ MidiView::MidiView (std::shared_ptr<MidiTrack> mt,
MidiView::MidiView (MidiView const & other)
: _editing_context (other.editing_context())
: sigc::trackable (other)
, _editing_context (other.editing_context())
, _midi_context (other.midi_context())
, _midi_region (other.midi_region())
, _active_notes(0)
@ -190,6 +191,12 @@ MidiView::set_track (std::shared_ptr<MidiTrack> mt)
if (_midi_track) {
_midi_track->DropReferences.connect (track_going_away_connection, invalidator (*this), boost::bind (&MidiView::track_going_away, this), gui_context());
if (_midi_track->triggerbox()->record_enabled()) {
begin_write ();
} else {
end_write ();
}
}
}
@ -1516,6 +1523,7 @@ MidiView::apply_note_range (uint8_t min, uint8_t max, bool force)
void
MidiView::begin_write()
{
std::cerr << "MV::begin write\n";
if (_active_notes) {
delete[] _active_notes;
}
@ -1531,8 +1539,9 @@ MidiView::begin_write()
void
MidiView::end_write()
{
std::cerr << "MV::end write\n";
delete[] _active_notes;
_active_notes = 0;
_active_notes = nullptr;
_marked_for_selection.clear();
_marked_for_velocity.clear();
}
@ -1593,6 +1602,9 @@ MidiView::start_playing_midi_chord (vector<std::shared_ptr<NoteType> > notes)
bool
MidiView::note_in_region_time_range (const std::shared_ptr<NoteType> note) const
{
if (!_midi_region) {
return true;
}
const std::shared_ptr<ARDOUR::MidiRegion> midi_reg = midi_region();
return (timepos_t (note->time()) >= _midi_region->start()) && (timepos_t (note->time()) < _midi_region->start() + _midi_region->length());
}
@ -1600,6 +1612,10 @@ MidiView::note_in_region_time_range (const std::shared_ptr<NoteType> note) const
bool
MidiView::note_in_region_range (const std::shared_ptr<NoteType> note, bool& visible) const
{
if (!_midi_region) {
return true;
}
const std::shared_ptr<ARDOUR::MidiRegion> midi_reg = midi_region();
const bool outside = !note_in_region_time_range (note);
@ -1628,63 +1644,15 @@ MidiView::update_note (NoteBase* note)
void
MidiView::update_sustained (Note* ev)
{
const std::shared_ptr<ARDOUR::MidiRegion> mr = midi_region();
std::shared_ptr<NoteType> note = ev->note();
const timepos_t note_start (note->time());
timepos_t note_end (note->end_time());
/* The note is drawn as a child item of this region view, so its
* coordinate system is relative to the region view. This means that x0
* and x1 are pixel offsets relative to beginning of the region (view)
*/
/* compute absolute time where the start of the source is
*/
const timepos_t session_source_start = _midi_region->source_position();
/* this computes the number of samples from the start of the region of the start of the
* note. We add the source start to get to the absolute time of the
* note, then subtract the start of the region
*/
const samplepos_t note_start_samples = _midi_region->position().distance ((note_start + session_source_start)).samples();
const double x0 = _editing_context.sample_to_pixel (note_start_samples);
double x1;
const double y0 = 1 + floor(note_to_y(note->note()));
double y1;
if (note->length() == Temporal::Beats()) {
/* special case actual zero-length notes */
x1 = x0 + 1.;
} else if (note->end_time() != std::numeric_limits<Temporal::Beats>::max()) {
/* normal note */
const Temporal::Beats source_end ((_midi_region->start() + _midi_region->length()).beats());
if (!_extensible && note->end_time() > source_end) {
note_end = timepos_t (source_end);
}
const samplepos_t note_end_samples = _midi_region->position().distance ((session_source_start + note_end)).samples();
x1 = std::max(1., _editing_context.sample_to_pixel (note_end_samples));
double x0, x1, y0, y1;
if (_midi_region) {
region_update_sustained (ev, x0, x1, y0, y1);
} else {
/* nascent note currently being recorded, noteOff has not yet arrived */
x1 = std::max(1., _editing_context.duration_to_pixels (_midi_region->length()));
clip_capture_update_sustained (ev, x0, x1, y0, y1);
}
y1 = y0 + std::max(1., floor(note_height()) - 1);
ev->set (ArdourCanvas::Rect (x0, y0, x1, y1));
ev->set_velocity (note->velocity()/127.0);
@ -1713,8 +1681,111 @@ MidiView::update_sustained (Note* ev)
const uint32_t base_col = ev->base_color();
ev->set_fill_color (base_col);
ev->set_outline_color (ev->calculate_outline(base_col, ev->selected()));
}
void
MidiView::clip_capture_update_sustained (Note *ev, double& x0, double& x1, double& y0, double& y1)
{
std::shared_ptr<NoteType> note = ev->note();
const timepos_t note_start (note->time());
timepos_t note_end (note->end_time());
x0 = _editing_context.sample_to_pixel (note_start.samples());
y0 = 1 + floor(note_to_y(note->note()));
if (note->length() == Temporal::Beats()) {
/* special case actual zero-length notes */
x1 = x0 + 1.;
} else if (note->end_time() != std::numeric_limits<Temporal::Beats>::max()) {
/* normal note */
#warning paul make this use the distance captured so far
const Temporal::Beats source_end (4,0);
if (!_extensible && note->end_time() > source_end) {
note_end = timepos_t (source_end);
}
#warning paul this needs to use the correct part of the tempo map, which will start at SlotArmInfo::start_samples
const samplepos_t note_end_samples = note_end.samples();
x1 = std::max(1., _editing_context.sample_to_pixel (note_end_samples));
} else {
/* nascent note currently being recorded, noteOff has not yet arrived */
#warning paul make this use the distance captured so far
x1 = std::max(1., _editing_context.duration_to_pixels (timecnt_t (Temporal::Beats (1, 0))));
}
y1 = y0 + std::max(1., floor(note_height()) - 1);
}
void
MidiView::region_update_sustained (Note *ev, double& x0, double& x1, double& y0, double& y1)
{
const std::shared_ptr<ARDOUR::MidiRegion> mr = midi_region();
std::shared_ptr<NoteType> note = ev->note();
const timepos_t note_start (note->time());
timepos_t note_end (note->end_time());
/* The note is drawn as a child item of this region view, so its
* coordinate system is relative to the region view. This means that x0
* and x1 are pixel offsets relative to beginning of the region (view)
*/
/* compute absolute time where the start of the source is
*/
const timepos_t session_source_start = _midi_region->source_position();
/* this computes the number of samples from the start of the region of the start of the
* note. We add the source start to get to the absolute time of the
* note, then subtract the start of the region
*/
const samplepos_t note_start_samples = _midi_region->position().distance ((note_start + session_source_start)).samples();
x0 = _editing_context.sample_to_pixel (note_start_samples);
y0 = 1 + floor(note_to_y(note->note()));
if (note->length() == Temporal::Beats()) {
/* special case actual zero-length notes */
x1 = x0 + 1.;
} else if (note->end_time() != std::numeric_limits<Temporal::Beats>::max()) {
/* normal note */
const Temporal::Beats source_end ((_midi_region->start() + _midi_region->length()).beats());
if (!_extensible && note->end_time() > source_end) {
note_end = timepos_t (source_end);
}
const samplepos_t note_end_samples = _midi_region->position().distance ((session_source_start + note_end)).samples();
x1 = std::max(1., _editing_context.sample_to_pixel (note_end_samples));
} else {
/* nascent note currently being recorded, noteOff has not yet arrived */
x1 = std::max(1., _editing_context.duration_to_pixels (_midi_region->length()));
}
y1 = y0 + std::max(1., floor(note_height()) - 1);
}
void
MidiView::update_hit (Hit* ev)
{
@ -4220,6 +4291,8 @@ MidiView::set_step_edit_cursor_width (Temporal::Beats beats)
void
MidiView::clip_data_recorded ()
{
std::cerr << "cd recorded, mt " << _midi_track << std::endl;
if (!_midi_track) {
return;
}

View File

@ -643,6 +643,8 @@ class MidiView : public virtual sigc::trackable, public LineMerger
void join_notes_on_channel (int channel);
void add_split_notes ();
void region_update_sustained (Note *, double&, double&, double&, double&);
void clip_capture_update_sustained (Note *, double&, double&, double&, double&);
};

View File

@ -387,17 +387,15 @@ TriggerPage::selection_changed ()
{
Selection& selection (Editor::instance ().get_selection ());
/* hide everything */
_slot_prop_box.hide ();
_audio_trig_box.hide ();
_midi_trig_box.hide ();
_midi_editor->viewport().hide ();
_parameter_box.hide ();
std::cerr << "here, st = " << selection.triggers.size() << std::endl;
if (!selection.triggers.empty ()) {
TriggerSelection ts = selection.triggers;
TriggerEntry* entry = *ts.begin ();
@ -419,17 +417,22 @@ TriggerPage::selection_changed ()
_midi_editor->set_box (ref.box());
std::shared_ptr<MidiTrack> mt = std::dynamic_pointer_cast<MidiTrack> (entry->strip().stripable());
assert (mt);
_midi_editor->set_track (mt);
if (trigger->the_region()) {
std::shared_ptr<MidiRegion> mr = std::dynamic_pointer_cast<MidiRegion> (trigger->the_region());
if (mr) {
std::shared_ptr<MidiTrack> mt = std::dynamic_pointer_cast<MidiTrack> (entry->strip().stripable());
_midi_editor->set_region (mt, ref.slot(), mr);
_midi_editor->viewport().show ();
_midi_editor->set_region (mr);
}
}
_midi_editor->viewport().show ();
}
_parameter_box.show ();
}
}