libardour APIs for Sequence::shift (timepos_t const &)

A way to move all MIDI data in a Sequence later in time.

This is likely not finished, and may need a new signal for
notifications
This commit is contained in:
Paul Davis 2025-04-05 17:23:17 -06:00
parent 9c0c3309e6
commit 4ee709af7b
7 changed files with 110 additions and 1 deletions

View file

@ -83,10 +83,25 @@ public:
protected: protected:
std::shared_ptr<MidiModel> _model; std::shared_ptr<MidiModel> _model;
const std::string _name; const std::string _name;
}; };
class LIBARDOUR_API ShiftCommand : public DiffCommand {
public:
ShiftCommand (std::shared_ptr<MidiModel> m, std::string const & name, TimeType distance);
ShiftCommand (std::shared_ptr<MidiModel> m, const XMLNode& node);
void operator() ();
void undo ();
int set_state (const XMLNode&, int version);
XMLNode & get_state () const;
private:
TimeType _distance;
};
class LIBARDOUR_API NoteDiffCommand : public DiffCommand { class LIBARDOUR_API NoteDiffCommand : public DiffCommand {
public: public:

View file

@ -126,6 +126,7 @@ MidiModel::apply_diff_command_only (Command* cmd)
/* ************* DIFF COMMAND ********************/ /* ************* DIFF COMMAND ********************/
#define SHIFT_COMMAND_ELEMENT "ShiftCommand"
#define NOTE_DIFF_COMMAND_ELEMENT "NoteDiffCommand" #define NOTE_DIFF_COMMAND_ELEMENT "NoteDiffCommand"
#define DIFF_NOTES_ELEMENT "ChangedNotes" #define DIFF_NOTES_ELEMENT "ChangedNotes"
#define ADDED_NOTES_ELEMENT "AddedNotes" #define ADDED_NOTES_ELEMENT "AddedNotes"
@ -146,6 +147,55 @@ MidiModel::DiffCommand::DiffCommand(std::shared_ptr<MidiModel> m, const std::str
assert(_model); assert(_model);
} }
MidiModel::ShiftCommand::ShiftCommand (std::shared_ptr<MidiModel> m, std::string const & name, MidiModel::TimeType distance)
: DiffCommand (m, name)
, _distance (distance)
{
assert (_model);
}
MidiModel::ShiftCommand::ShiftCommand (std::shared_ptr<MidiModel> m, const XMLNode& node)
: DiffCommand (m, "")
{
assert (_model);
set_state (node, Stateful::loading_state_version);
// _name = string_compose (_("Shift MIDI by %1"), _distance.str());
}
void
MidiModel::ShiftCommand::operator() ()
{
_model->shift (_distance);
_model->ContentsChanged (); /* EMIT SIGNAL */
}
void
MidiModel::ShiftCommand::undo ()
{
_model->shift (-_distance);
_model->ContentsChanged (); /* EMIT SIGNAL */
}
int
MidiModel::ShiftCommand::set_state (XMLNode const & diff_command, int /* version */)
{
if (diff_command.name() != string (SHIFT_COMMAND_ELEMENT)) {
return 1;
}
diff_command.get_property (X_("distance"), _distance);
return 0;
}
XMLNode&
MidiModel::ShiftCommand::get_state () const
{
XMLNode* node = new XMLNode (SHIFT_COMMAND_ELEMENT);
node->set_property (X_("distance"), _distance);
return *node;
}
MidiModel::NoteDiffCommand::NoteDiffCommand (std::shared_ptr<MidiModel> m, const XMLNode& node) MidiModel::NoteDiffCommand::NoteDiffCommand (std::shared_ptr<MidiModel> m, const XMLNode& node)
: DiffCommand (m, "") : DiffCommand (m, "")
{ {

View file

@ -1041,6 +1041,8 @@ Region::modify_front_unchecked (timepos_t const & npos, bool reset_fade)
source_zero = timepos_t (source_position().time_domain()); // its actually negative, but this will work for us source_zero = timepos_t (source_position().time_domain()); // its actually negative, but this will work for us
} }
std::cerr << "source zero " << source_zero << std::endl;
if (new_position >= last) { /* can't trim it zero or negative length */ if (new_position >= last) { /* can't trim it zero or negative length */
return; return;
} }
@ -1059,6 +1061,8 @@ Region::modify_front_unchecked (timepos_t const & npos, bool reset_fade)
newlen = length() + (np.distance (position())); newlen = length() + (np.distance (position()));
} }
std::cerr << "tti " << np << ", " << newlen << std::endl;
trim_to_internal (np, newlen); trim_to_internal (np, newlen);
if (reset_fade) { if (reset_fade) {

View file

@ -1213,6 +1213,23 @@ ControlList::shift (timepos_t const& time, timecnt_t const& distance)
maybe_signal_changed (); maybe_signal_changed ();
} }
/* Note: timepos_t is used here instead of timecnt_t because there's an
* implicit origin for the magnitude of the distance.
*/
void
ControlList::simple_shift (timepos_t const & distance)
{
{
Glib::Threads::RWLock::WriterLock lm (_lock);
for (auto & e : _events) {
e->when = e->when + distance;
}
mark_dirty ();
}
maybe_signal_changed ();
}
void void
ControlList::modify (iterator iter, timepos_t const& time, double val) ControlList::modify (iterator iter, timepos_t const& time, double val)
{ {

View file

@ -1448,6 +1448,26 @@ Sequence<Time>::control_list_marked_dirty ()
set_edited (true); set_edited (true);
} }
template<typename Time>
void
Sequence<Time>::shift (Time const & d)
{
WriteLock rl (write_lock());
for (auto & n : _notes) {
n->set_time (n->time() + d);
}
for (auto & s : _sysexes) {
s->set_time (s->time() + d);
}
for (auto & p : _patch_changes) {
p->set_time (p->time() + d);
}
for (auto & [param,ctl] : _controls) {
ctl->list()->simple_shift (Temporal::timepos_t (d));
}
}
template<typename Time> template<typename Time>
void void
Sequence<Time>::dump (ostream& str, typename Sequence<Time>::const_iterator x, uint32_t limit) const Sequence<Time>::dump (ostream& str, typename Sequence<Time>::const_iterator x, uint32_t limit) const

View file

@ -141,6 +141,7 @@ public:
bool extend_to (Temporal::timepos_t const & ); bool extend_to (Temporal::timepos_t const & );
void slide (iterator before, Temporal::timecnt_t const & distance); void slide (iterator before, Temporal::timecnt_t const & distance);
void shift (Temporal::timepos_t const & before, Temporal::timecnt_t const & distance); void shift (Temporal::timepos_t const & before, Temporal::timecnt_t const & distance);
void simple_shift (Temporal::timepos_t const & distance);
void y_transform (std::function<double(double)> callback); void y_transform (std::function<double(double)> callback);
void list_merge (ControlList const& other, std::function<double(double, double)> callback); void list_merge (ControlList const& other, std::function<double(double, double)> callback);

View file

@ -319,6 +319,8 @@ public:
Time duration() const { return _duration; } Time duration() const { return _duration; }
void set_duration (Time const &); void set_duration (Time const &);
void shift (Time const &);
protected: protected:
bool _edited; bool _edited;
bool _overlapping_pitches_accepted; bool _overlapping_pitches_accepted;