MIDI combine (basically operational)

May need some tweaks to address notes that are cut off by the end of the region
This commit is contained in:
Paul Davis 2022-06-29 08:09:12 -06:00
parent ffc9239de5
commit 2f7f313f6d
7 changed files with 103 additions and 17 deletions

View File

@ -1518,14 +1518,10 @@ Editor::sensitize_the_right_region_actions (bool because_canvas_crossing)
_region_actions->get_action("show-region-list-editor")->set_sensitive (false);
_region_actions->get_action("show-region-properties")->set_sensitive (false);
_region_actions->get_action("rename-region")->set_sensitive (false);
if (have_audio) {
/* XXX need to check whether there is than 1 per
playlist, because otherwise this makes no sense.
*/
_region_actions->get_action("combine-regions")->set_sensitive (true);
} else {
_region_actions->get_action("combine-regions")->set_sensitive (false);
}
/* XXX need to check whether there is than 1 per
playlist, because otherwise this makes no sense.
*/
_region_actions->get_action("combine-regions")->set_sensitive (true);
} else if (rs.size() == 1) {
_region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
_region_actions->get_action("close-region-gaps")->set_sensitive (false);

View File

@ -2541,13 +2541,6 @@ void add_region_to_list (RegionView* rv, RegionList* l)
RegionView*
RouteTimeAxisView::combine_regions ()
{
/* as of may 2011, we do not offer uncombine for MIDI tracks
*/
if (!is_audio_track()) {
return 0;
}
if (!_view) {
return 0;
}

View File

@ -84,6 +84,9 @@ public:
std::set<Evoral::Parameter> contained_automation();
boost::shared_ptr<Region> combine (const RegionList&);
void uncombine (boost::shared_ptr<Region>);
protected:
void remove_dependents (boost::shared_ptr<Region> region);
void region_going_away (boost::weak_ptr<Region> region);

View File

@ -82,6 +82,8 @@ class LIBARDOUR_API MidiRegion : public Region
uint32_t chan_n = 0,
NoteMode mode = Sustained) const;
void merge (boost::shared_ptr<MidiRegion const>);
XMLNode& state () const;
int set_state (const XMLNode&, int version);

View File

@ -186,8 +186,8 @@ public:
void duplicate_range (TimelineRange&, float times);
void duplicate_ranges (std::list<TimelineRange>&, float times);
void nudge_after (timepos_t const & start, timecnt_t const & distance, bool forwards);
boost::shared_ptr<Region> combine (const RegionList&);
void uncombine (boost::shared_ptr<Region>);
virtual boost::shared_ptr<Region> combine (const RegionList&);
virtual void uncombine (boost::shared_ptr<Region>);
void fade_range (std::list<TimelineRange>&);
void remove_gaps (timecnt_t const & gap_threshold, timecnt_t const & leave_gap, boost::function<void (timepos_t, timecnt_t)> gap_callback);

View File

@ -35,6 +35,7 @@
#include "ardour/midi_source.h"
#include "ardour/midi_state_tracker.h"
#include "ardour/region_factory.h"
#include "ardour/region_sorters.h"
#include "ardour/rt_midibuffer.h"
#include "ardour/session.h"
#include "ardour/tempo.h"
@ -374,3 +375,52 @@ MidiPlaylist::rendered ()
{
return &_rendered;
}
boost::shared_ptr<Region>
MidiPlaylist::combine (RegionList const & rl)
{
RegionWriteLock rwl (this, true);
std::cerr << "combine " << rl.size() << " regions\n";
if (rl.size() < 2) {
return boost::shared_ptr<Region> ();
}
RegionList sorted (rl);
sorted.sort (RegionSortByLayerAndPosition());
boost::shared_ptr<Region> first = sorted.front();
RegionList::const_iterator i = sorted.begin();
++i;
#ifndef NDEBUG
for (auto const & r : rl) {
assert (boost::dynamic_pointer_cast<MidiRegion> (r));
}
#endif
boost::shared_ptr<MidiRegion> new_region = boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (first, true, true, &rwl.thawlist));
timepos_t pos (first->position());
remove_region_internal (first, rwl.thawlist);
std::cerr << "Remove " << first->name() << std::endl;
while (i != sorted.end()) {
new_region->merge (boost::dynamic_pointer_cast<MidiRegion> (*i));
remove_region_internal (*i, rwl.thawlist);
std::cerr << "Remove " << (*i)->name() << std::endl;
++i;
}
add_region_internal (new_region, pos, rwl.thawlist);
std::cerr << "Add " << new_region->name() << std::endl;
return new_region;
}
void
MidiPlaylist::uncombine (boost::shared_ptr<Region> r)
{
}

View File

@ -539,3 +539,45 @@ MidiRegion::set_name (const std::string& str)
return Region::set_name (str);
}
void
MidiRegion::merge (boost::shared_ptr<MidiRegion const> other_region)
{
Temporal::Beats last_event_time;
{
Source::WriterLock lm (midi_source(0)->mutex());
boost::shared_ptr<MidiModel const> other = other_region->model();
boost::shared_ptr<MidiModel> self = model();
Temporal::Beats other_region_start (other_region->start().beats());
Temporal::Beats other_region_end ((other_region->start() + other_region->length()).beats());
midi_source (0)->mark_streaming_midi_write_started (lm, Sustained);
for (Evoral::Sequence<Temporal::Beats>::const_iterator e = other->begin(); e != other->end(); ++e) {
if (e->time() < other_region_start) {
continue;
}
if (e->time() >= other_region_end) {
break;
}
Evoral::Event<Temporal::Beats> ev (*e, true);
Temporal::Beats abs_time = other_region->source_beats_to_absolute_time (ev.time()).beats ();
Temporal::Beats srt = absolute_time_to_source_beats (timepos_t (abs_time));
ev.set_time (srt);
self->append (ev, Evoral::next_event_id());
last_event_time = abs_time;
}
midi_source (0)->mark_streaming_write_completed (lm);
}
Temporal::Beats len = last_event_time - position().beats();
set_length (timecnt_t (len, position()));
}