In the presence of tempo-changes distinguishing between offsets and
absolute positions is signficant. It is only valid to convert absolute
times using the tempo-map
Furthermore since GUI zoom-factor is time-invariant (samples per pixel),
all GUI operations must explictly use samples (or timecnt). It is not
valid (and problematic) to use use a location dependent timepos.
1. leave tertiary-scroll for navigation and primary scroll for session timeline zoom
2. unmodified scroll in edit mode scrolls contents
3. secondary-scroll zooms in and out on contents (i.e. vertical zoom for MIDI)
4. primary-secondary scroll has the just-one-edge behavior previously provided
This also fixes Menu > Edit Delete "delete MIDI" operation.
Pressing backspace/delete calls "Delete Selection" which is
unrelated to MRV::cut_copy_clear.
Note position in samples must be calculated using absolute position
on the timeline. Otherwise the tempo-map is not applied correctly.
Previously this caused issues since the position was first
offset back by _region->position() - time relative to region left
edge - and then the tempo-map was applied.
Another solution identically would be:
(note_start + session_source_start).samples() - _region->position().samples()
this prevents the case where have enabled snap, and you add a note that
appears to be on a bar line. but actually it is {some Grid value} off,
it just looks right because of pixel rounding.
these functions operate on the _note_diff_command,
which is explicitly a NoteDiff, not a generic DiffCommand
also fix a few thinkos where the ambiguous naming led to errors
::model_changed() is used when the model has changed (eg. new notes or some
notes deleted); ::view_changed() is used when only some view parameter (e.g.
zoom, scroll, track height etc) has been altered.
Not fully functional yet (::view_chanted() ignores scroll)
This also requires a change in the type of reference held by
a MidiAutomationListBinder.
Both the MidiSource and MidiModel have a reference to each other, and it is
important that we avoid circular references to avoid problems with object
destruction. We had been accomplishing this by having the Model hold a
weak_ptr<MidiSource>. However, the lifetime of a MidiSource and its MidiModel
are coincident and there's really no need to use a smart ptr at all. A normal
reference is just fine. However, due to constructors that accept a serialized
state, we cannot use an actual reference (we cannot set the constructor in the
initializer list), so we use a bare ptr instead.
This forces a similar change in MidiAutomationListBinder, which also maintains
a reference to the Source. However, the only purpose of this object is to
ensure that if the Source is destroyed, relevant commands will be removed from
the undo/redo history, and so all that matters here is that the binder connects
to the Destroyed signal of the source, and arranges for its own destruction
when received.
Note that the previous construction of the binder, actually holding a
shared_ptr<MidiSource> would appear have prevented the Destroyed signal from
ever being emitted (from ~Destructible), and so this may also be a bug fix that
allows MidiSources to actually be deleted (the memory object, not the file).