We should not call CueEditor::rec_enable_change() from CueEditor::trigger_arm_change()
because (a) the rec-enable change is coming anyway (b) at the time a trigger is
disarmed, the triggerbox is still rec-enabled. This means that in the end, a MidiView
gets its ::begin_write() method called again before we call ::model_changed()
and that leads it to have non-null _unfinished_live_notes (i.e. we're actively
recording, so do thing).
This allows the user to not have to aim for such precise timing, since they can
hold the note down during the count-in.
At some point the question will arise why we don't do this for controllers
etc. too.
This is a bit ironic, since EventSink is an abstract base class for MidiBuffer, which is
already supported for a flush_notes() call. But we use MidiBuffer::push_back() for that,
mostly for efficiency purposes (write() can insert an event at any time).
There is some weird behavior here, where causing a refill of the listview (e.g. by changing
the status of a port flag) doesn't interact correctly with the scrollbar. I can't find
a solution at the present time, so just grow the listview vertical size to accomodate a lot
more (potential) MIDI ports in both lists (without altering the prefs dialog size)
Allow for 192kHz session (needs testing, by ear and
by down-sampling to 48k vs. running directly at 48k, etc)
Also prevent plugin from loading when sample-rate is out of bounds.
Previously the plugin loaded but was pitched up when the sample
rate exceeded 96k.
This properly handles missing write permissions (that previously
crashed when trying to close the archive).
Also report and error on disk-full or other write failures
such as 4GB file limit.
This issue could be seen when dragging an arrangement marker beyond the
bottom of the list in the right edge.
IIUC, std::reverse_iterator<Iter>::operator* creates a temporary iterator
which it then dereferences. This is a problem because what we are
derefencing is a Gtk::TreeIter<Gtk::TreeRow>. gtkmm documentation for
Gtk::TreeIter< T >::operator* states, "The returned reference is
implemented by casting from *this, and so the returned reference is only
valid while this iter is." Additionally, cpp documentation for
std::reverse_iterator states, "std::reverse_iterator does not work with
iterators whose dereference returns a reference to a member of *this."
We also are not advancing this iterator at all, so whether it is reverse
or not is irrelevant (we just want the last one). Thus, *prev(rows.end ())
instead of *rows.rbegin ().
If walking the grid by bar, but points are closer than that, we could end up
with the wrong TempoMetric being used to compute various time domain
conversions (which tends to leads to abort()).
This small change makes sure that we keep looking for more points if we have
not yet reached the next grid point (e.g. bar).