import_pt: Fix for multichannel tracks and regions #9705
Also speeds up PT imports during region creation. This is because regions are imported immediately when sources are grouped into multichannels rather than doing it in another pass
This commit is contained in:
@@ -1364,7 +1364,7 @@ public:
|
||||
void import_pt_rest (PTFFormat& ptf);
|
||||
bool import_sndfile_as_region (std::string path, SrcQuality quality, timepos_t& pos, SourceList& sources, ImportStatus& status, uint32_t current, uint32_t total);
|
||||
|
||||
struct ptflookup {
|
||||
typedef struct ptflookup {
|
||||
uint16_t index1;
|
||||
uint16_t index2;
|
||||
PBD::ID id;
|
||||
@@ -1372,9 +1372,8 @@ public:
|
||||
bool operator ==(const struct ptflookup& other) {
|
||||
return (this->index1 == other.index1);
|
||||
}
|
||||
};
|
||||
std::vector<struct ptflookup> ptfwavpair;
|
||||
SourceList pt_imported_sources;
|
||||
} PtfLookup;
|
||||
std::vector<PtfLookup> ptfregpair;
|
||||
|
||||
enum TimingTypes {
|
||||
OverallProcess = 0,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2023 Damien Zammit <damien@zamaudio.com>
|
||||
* Copyright (C) 2018-2025 Damien Zammit <damien@zamaudio.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -73,190 +73,222 @@ struct PlaylistState {
|
||||
XMLNode* before;
|
||||
};
|
||||
|
||||
bool
|
||||
Session::import_sndfile_as_region (string path, SrcQuality quality, timepos_t& pos, SourceList& sources, ImportStatus& status, uint32_t current, uint32_t total)
|
||||
static bool
|
||||
import_pt_sndfile (Session* s, PTFFormat& ptf, PTFFormat::wav_t& w, std::string path, std::vector<Session::PtfLookup>& wavchans,
|
||||
SourceList& sources, ImportStatus& status, uint32_t current, uint32_t total)
|
||||
{
|
||||
/* Import the source */
|
||||
bool ok = true;
|
||||
Session::PtfLookup p;
|
||||
|
||||
status.paths.clear();
|
||||
status.paths.push_back(path);
|
||||
status.current = current;
|
||||
status.total = total;
|
||||
status.freeze = false;
|
||||
status.quality = quality;
|
||||
status.quality = SrcBest;
|
||||
status.replace_existing_source = false;
|
||||
status.split_midi_channels = false;
|
||||
status.import_markers = false;
|
||||
status.done = false;
|
||||
status.cancel = false;
|
||||
|
||||
import_files(status);
|
||||
status.progress = 1.0;
|
||||
sources.clear();
|
||||
/* Check if no sound file was passed in */
|
||||
if (path == "") {
|
||||
/* ptformat knows length of sources *in PT sample rate*
|
||||
* BUT if ardour user later resolves missing file,
|
||||
* it won't be resampled, so we can only do this
|
||||
* when sample rates are matching
|
||||
*/
|
||||
if (s->sample_rate () == ptf.sessionrate ()) {
|
||||
/* Insert reference to missing source */
|
||||
samplecnt_t sourcelen = w.length;
|
||||
XMLNode srcxml (X_("Source"));
|
||||
srcxml.set_property ("name", w.filename);
|
||||
srcxml.set_property ("type", "audio");
|
||||
srcxml.set_property ("id", PBD::ID ().to_s ());
|
||||
std::shared_ptr<ARDOUR::Source> source = SourceFactory::createSilent (*s, srcxml, sourcelen, s->sample_rate ());
|
||||
sources.push_back (source);
|
||||
|
||||
/* FIXME: There is no way to tell if cancel button was pressed
|
||||
* or if the file failed to import, just that one of these occurred.
|
||||
* We want status.cancel to reflect the user's choice only
|
||||
*/
|
||||
if (status.cancel && status.current > current) {
|
||||
/* Succeeded to import file, assume user hit cancel */
|
||||
return false;
|
||||
} else if (status.cancel && status.current == current) {
|
||||
/* Failed to import file, assume user did not hit cancel */
|
||||
status.cancel = false;
|
||||
return false;
|
||||
}
|
||||
p.index1 = w.index;
|
||||
p.index2 = 0; /* unused */
|
||||
p.id = sources.front ()->id ();
|
||||
wavchans.push_back (p);
|
||||
|
||||
sources.push_back(status.sources.front());
|
||||
|
||||
/* Put the source on a region */
|
||||
vector<std::shared_ptr<Region> > regions;
|
||||
string region_name;
|
||||
bool use_timestamp;
|
||||
|
||||
use_timestamp = (pos == timepos_t::max (Temporal::AudioTime));
|
||||
|
||||
/* take all the sources we have and package them up as a region */
|
||||
|
||||
region_name = region_name_from_path (status.paths.front(), (sources.size() > 1), false);
|
||||
|
||||
/* we checked in import_sndfiles() that there were not too many */
|
||||
|
||||
while (RegionFactory::region_by_name (region_name)) {
|
||||
region_name = bump_name_once (region_name, '.');
|
||||
}
|
||||
|
||||
PropertyList plist;
|
||||
|
||||
plist.add (ARDOUR::Properties::start, timepos_t (0));
|
||||
plist.add (ARDOUR::Properties::length, timecnt_t (sources[0]->length (), pos));
|
||||
plist.add (ARDOUR::Properties::name, region_name);
|
||||
plist.add (ARDOUR::Properties::layer, 0);
|
||||
plist.add (ARDOUR::Properties::whole_file, true);
|
||||
plist.add (ARDOUR::Properties::external, true);
|
||||
|
||||
std::shared_ptr<Region> r = RegionFactory::create (sources, plist);
|
||||
|
||||
if (use_timestamp && std::dynamic_pointer_cast<AudioRegion>(r)) {
|
||||
std::dynamic_pointer_cast<AudioRegion>(r)->special_set_position(sources[0]->natural_position());
|
||||
}
|
||||
|
||||
regions.push_back (r);
|
||||
|
||||
/* if we're creating a new track, name it after the cleaned-up
|
||||
* and "merged" region name.
|
||||
*/
|
||||
|
||||
int n = 0;
|
||||
|
||||
for (vector<std::shared_ptr<Region> >::iterator r = regions.begin(); r != regions.end(); ++r, ++n) {
|
||||
std::shared_ptr<AudioRegion> ar = std::dynamic_pointer_cast<AudioRegion> (*r);
|
||||
|
||||
if (use_timestamp) {
|
||||
if (ar) {
|
||||
|
||||
/* get timestamp for this region */
|
||||
|
||||
const std::shared_ptr<Source> s (ar->sources().front());
|
||||
const std::shared_ptr<AudioSource> as = std::dynamic_pointer_cast<AudioSource> (s);
|
||||
|
||||
assert (as);
|
||||
|
||||
if (as->natural_position() != 0) {
|
||||
pos = as->natural_position();
|
||||
} else {
|
||||
pos = timepos_t (pos.time_domain ());
|
||||
}
|
||||
} else {
|
||||
/* should really get first position in MIDI file, but for now, use 0 */
|
||||
pos = timepos_t (pos.time_domain());
|
||||
}
|
||||
warning << string_compose (_("PT Import : MISSING `%1`, inserting ref to missing source"), w.filename) << endmsg;
|
||||
} else {
|
||||
/* no sound file and mismatching sample rate to ptf */
|
||||
warning << string_compose (_("PT Import : MISSING `%1`, please check Audio Files"), w.filename) << endmsg;
|
||||
ok = false;
|
||||
}
|
||||
status.done = false;
|
||||
} else {
|
||||
/* Import the source */
|
||||
status.paths.push_back(path);
|
||||
status.done = false;
|
||||
s->import_files(status);
|
||||
|
||||
/* FIXME: There is no way to tell if cancel button was pressed
|
||||
* or if the file failed to import, just that one of these occurred.
|
||||
* We want status.cancel to reflect the user's choice only
|
||||
*/
|
||||
if (status.cancel && status.current > current) {
|
||||
/* Succeeded to import file, assume user hit cancel */
|
||||
return false;
|
||||
} else if (status.cancel && status.current == current) {
|
||||
/* Failed to import file, assume user did not hit cancel */
|
||||
status.cancel = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
assert (status.sources.size () > 0);
|
||||
|
||||
sources.push_back(status.sources.front());
|
||||
|
||||
p.index1 = w.index;
|
||||
p.index2 = 0; /* unused */
|
||||
p.id = sources.front ()->id ();
|
||||
wavchans.push_back (p);
|
||||
}
|
||||
|
||||
for (SourceList::iterator x = sources.begin(); x != sources.end(); ++x) {
|
||||
SourceFactory::setup_peakfile (*x, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Session::import_pt_sources (PTFFormat& ptf, ImportStatus& status)
|
||||
static bool
|
||||
import_pt_source_channels_or_empty (Session* s, PTFFormat& ptf, std::vector<PTFFormat::wav_t>& ws, std::vector<Session::PtfLookup>& wavchans,
|
||||
SourceList& ch_sources, ImportStatus& status, uint32_t current, uint32_t total)
|
||||
{
|
||||
bool ok, onefailed;
|
||||
string fullpath;
|
||||
bool ok = false;
|
||||
bool onefailed = false;
|
||||
timepos_t pos = timepos_t::max (Temporal::AudioTime);
|
||||
|
||||
vector<PTFFormat::wav_t>::const_iterator w;
|
||||
uint32_t wth = 0;
|
||||
onefailed = false;
|
||||
for (std::vector<PTFFormat::wav_t>::iterator w = ws.begin (); w != ws.end (); ++w) {
|
||||
ok = true;
|
||||
|
||||
SourceList just_one_src;
|
||||
|
||||
ptfwavpair.clear();
|
||||
pt_imported_sources.clear();
|
||||
status.clear();
|
||||
|
||||
for (w = ptf.audiofiles ().begin (); w != ptf.audiofiles ().end () && !status.cancel; ++w) {
|
||||
struct ptflookup p;
|
||||
wth++;
|
||||
ok = false;
|
||||
/* Try audio file */
|
||||
fullpath = Glib::build_filename (Glib::path_get_dirname (ptf.path ()), "Audio Files");
|
||||
fullpath = Glib::build_filename (fullpath, w->filename);
|
||||
if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS)) {
|
||||
just_one_src.clear();
|
||||
ok = import_sndfile_as_region (fullpath, SrcBest, pos, just_one_src, status, wth, ptf.audiofiles ().size ());
|
||||
/* fullpath has a valid audio file - load it */
|
||||
ok = import_pt_sndfile (s, ptf, *w, fullpath, wavchans, ch_sources, status, current, total);
|
||||
} else {
|
||||
/* Try fade file */
|
||||
fullpath = Glib::build_filename (Glib::path_get_dirname (ptf.path ()), "Fade Files");
|
||||
fullpath = Glib::build_filename (fullpath, w->filename);
|
||||
if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS)) {
|
||||
just_one_src.clear();
|
||||
ok = import_sndfile_as_region (fullpath, SrcBest, pos, just_one_src, status, wth, ptf.audiofiles ().size ());
|
||||
/* fullpath has a valid fade file - load it */
|
||||
ok = import_pt_sndfile (s, ptf, *w, fullpath, wavchans, ch_sources, status, current, total);
|
||||
} else {
|
||||
onefailed = true;
|
||||
|
||||
/* ptformat knows length of sources *in PT sample rate*
|
||||
* BUT if ardour user later resolves missing file,
|
||||
* it won't be resampled, so we can only do this
|
||||
* when sample rates are matching
|
||||
*/
|
||||
if (sample_rate () == ptf.sessionrate ()) {
|
||||
/* Insert reference to missing source */
|
||||
samplecnt_t sourcelen = w->length;
|
||||
XMLNode srcxml (X_("Source"));
|
||||
srcxml.set_property ("name", w->filename);
|
||||
srcxml.set_property ("type", "audio");
|
||||
srcxml.set_property ("id", PBD::ID ().to_s ());
|
||||
std::shared_ptr<Source> source = SourceFactory::createSilent (*this, srcxml, sourcelen, sample_rate ());
|
||||
p.index1 = w->index;
|
||||
p.id = source->id ();
|
||||
ptfwavpair.push_back (p);
|
||||
pt_imported_sources.push_back (source);
|
||||
warning << string_compose (_("PT Import : MISSING `%1`, inserting ref to missing source"), fullpath) << endmsg;
|
||||
} else {
|
||||
warning << string_compose (_("PT Import : MISSING `%1`, please check Audio Files"), fullpath) << endmsg;
|
||||
}
|
||||
/* no sound file - fill source with silence */
|
||||
ok = import_pt_sndfile (s, ptf, *w, "", wavchans, ch_sources, status, current, total);
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
p.index1 = w->index;
|
||||
p.id = just_one_src.back ()->id ();
|
||||
|
||||
ptfwavpair.push_back (p);
|
||||
pt_imported_sources.push_back (just_one_src.back ());
|
||||
} else {
|
||||
if (!ok) {
|
||||
onefailed = true;
|
||||
} else {
|
||||
current++;
|
||||
}
|
||||
}
|
||||
|
||||
if (pt_imported_sources.empty ()) {
|
||||
if (onefailed)
|
||||
return false;
|
||||
|
||||
/* now we have ch_sources with either silent sources or populated with sound file backed sources,
|
||||
* and wavchans with vector of matching ids per channel */
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Session::import_pt_sources (PTFFormat& ptf, ImportStatus& status)
|
||||
{
|
||||
bool ok = false;
|
||||
bool onefailed = false;
|
||||
bool allfailed = true;
|
||||
int src_cnt = 1;
|
||||
string base_name;
|
||||
map<string,vector<PTFFormat::wav_t> > multi_ch;
|
||||
vector<Session::PtfLookup> ptfwavpair;
|
||||
SourceList source_group;
|
||||
vector<std::shared_ptr<Region> > regions;
|
||||
timepos_t pos;
|
||||
|
||||
status.clear ();
|
||||
ptfregpair.clear ();
|
||||
|
||||
/* Collect multi channel info from sources */
|
||||
for (vector<PTFFormat::wav_t>::const_iterator w = ptf.audiofiles ().begin ();
|
||||
w != ptf.audiofiles ().end (); ++w) {
|
||||
base_name = region_name_from_path (w->filename, true, false);
|
||||
multi_ch[base_name].push_back(*w);
|
||||
}
|
||||
|
||||
/* Import all other regions for potentially single or multi channel grouped sources */
|
||||
for (map<string,vector<PTFFormat::wav_t> >::iterator m = multi_ch.begin (); m != multi_ch.end (); ++m) {
|
||||
ptfwavpair.clear ();
|
||||
source_group.clear ();
|
||||
ok = import_pt_source_channels_or_empty (this, ptf, multi_ch[(*m).first], ptfwavpair, source_group,
|
||||
status, src_cnt, ptf.audiofiles ().size ());
|
||||
if (!ok) {
|
||||
onefailed = true;
|
||||
continue;
|
||||
} else {
|
||||
allfailed = false;
|
||||
src_cnt += multi_ch[(*m).first].size (); /* progress bar is 1-based */
|
||||
}
|
||||
|
||||
/* Import whole_file region for potentially single or multi channel grouped sources */
|
||||
{
|
||||
Session::PtfLookup rp;
|
||||
PropertyList plist;
|
||||
|
||||
plist.add (ARDOUR::Properties::start, timepos_t (0));
|
||||
plist.add (ARDOUR::Properties::length, multi_ch[(*m).first][0].length);
|
||||
plist.add (ARDOUR::Properties::name, (*m).first);
|
||||
plist.add (ARDOUR::Properties::layer, 0);
|
||||
plist.add (ARDOUR::Properties::whole_file, true);
|
||||
plist.add (ARDOUR::Properties::external, true);
|
||||
|
||||
std::shared_ptr<Region> rg = RegionFactory::create (source_group, plist);
|
||||
regions.push_back (rg);
|
||||
|
||||
rp.id = regions.back ()->id ();
|
||||
rp.index1 = -1; /* Special: this region is maybe from two merged srcs */
|
||||
ptfregpair.push_back (rp);
|
||||
}
|
||||
|
||||
/* Create regions only for this multi channel source group */
|
||||
for (vector<PTFFormat::region_t>::const_iterator r = ptf.regions ().begin ();
|
||||
r != ptf.regions ().end (); ++r) {
|
||||
for (vector<Session::PtfLookup>::iterator p = ptfwavpair.begin ();
|
||||
p != ptfwavpair.end (); ++p) {
|
||||
if (p->index1 == r->wave.index) {
|
||||
/* Create an ardour region from multi channel source group */
|
||||
Session::PtfLookup rp;
|
||||
PropertyList plist;
|
||||
|
||||
plist.add (ARDOUR::Properties::start, timepos_t (r->sampleoffset));
|
||||
plist.add (ARDOUR::Properties::length, r->length);
|
||||
plist.add (ARDOUR::Properties::name, (*m).first);
|
||||
plist.add (ARDOUR::Properties::layer, 0);
|
||||
plist.add (ARDOUR::Properties::whole_file, false);
|
||||
plist.add (ARDOUR::Properties::external, true);
|
||||
|
||||
std::shared_ptr<Region> rg = RegionFactory::create (source_group, plist);
|
||||
regions.push_back (rg);
|
||||
|
||||
rp.id = regions.back ()->id ();
|
||||
rp.index1 = r->index;
|
||||
ptfregpair.push_back (rp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allfailed) {
|
||||
error << _("Failed to find any audio for PT import") << endmsg;
|
||||
} else if (onefailed) {
|
||||
warning << _("Failed to load one or more of the audio files for PT import, see above list") << endmsg;
|
||||
} else {
|
||||
for (SourceList::iterator x = status.sources.begin (); x != status.sources.end (); ++x) {
|
||||
SourceFactory::setup_peakfile (*x, true);
|
||||
}
|
||||
info << _("All audio files found for PT import!") << endmsg;
|
||||
}
|
||||
|
||||
@@ -270,102 +302,99 @@ Session::import_pt_sources (PTFFormat& ptf, ImportStatus& status)
|
||||
void
|
||||
Session::import_pt_rest (PTFFormat& ptf)
|
||||
{
|
||||
vector<std::shared_ptr<Region> > regions;
|
||||
bool ok;
|
||||
std::shared_ptr<ARDOUR::Track> track;
|
||||
ARDOUR::PluginInfoPtr instrument;
|
||||
vector<string> to_import;
|
||||
string fullpath;
|
||||
uint32_t srate = sample_rate ();
|
||||
timepos_t latest = timepos_t (0);
|
||||
bool ok;
|
||||
|
||||
vector<struct ptflookup> ptfregpair;
|
||||
SourceList all_ch_srcs;
|
||||
|
||||
SourceList just_one_src;
|
||||
RouteList routes;
|
||||
list<std::shared_ptr<AudioTrack> > tracks;
|
||||
std::shared_ptr<AudioTrack> existing_track;
|
||||
uint16_t nth = 0;
|
||||
struct ptflookup utr;
|
||||
Session::PtfLookup utr;
|
||||
vector<midipair> uniquetr;
|
||||
|
||||
vector<PlaylistState> playlists;
|
||||
vector<PlaylistState>::iterator pl;
|
||||
|
||||
just_one_src.clear();
|
||||
all_ch_srcs.clear();
|
||||
uniquetr.clear();
|
||||
ptfregpair.clear();
|
||||
to_import.clear();
|
||||
regions.clear();
|
||||
playlists.clear();
|
||||
|
||||
for (vector<PTFFormat::region_t>::const_iterator a = ptf.regions ().begin ();
|
||||
a != ptf.regions ().end (); ++a) {
|
||||
for (vector<struct ptflookup>::iterator p = ptfwavpair.begin ();
|
||||
p != ptfwavpair.end (); ++p) {
|
||||
if ((p->index1 == a->wave.index) && (strcmp (a->wave.filename.c_str (), "") != 0)) {
|
||||
for (SourceList::iterator x = pt_imported_sources.begin (); x != pt_imported_sources.end (); ++x) {
|
||||
if ((*x)->id () == p->id) {
|
||||
/* Matched an uncreated ptf region to ardour region */
|
||||
struct ptflookup rp;
|
||||
PropertyList plist;
|
||||
std::map<std::string, shared_ptr<AudioTrack> > track_map;
|
||||
|
||||
plist.add (ARDOUR::Properties::start, timepos_t (a->sampleoffset));
|
||||
plist.add (ARDOUR::Properties::length, a->length);
|
||||
plist.add (ARDOUR::Properties::name, a->name);
|
||||
plist.add (ARDOUR::Properties::layer, 0);
|
||||
plist.add (ARDOUR::Properties::whole_file, false);
|
||||
plist.add (ARDOUR::Properties::external, true);
|
||||
|
||||
just_one_src.clear ();
|
||||
just_one_src.push_back (*x);
|
||||
|
||||
std::shared_ptr<Region> r = RegionFactory::create (just_one_src, plist);
|
||||
regions.push_back (r);
|
||||
|
||||
rp.id = regions.back ()->id ();
|
||||
rp.index1 = a->index;
|
||||
ptfregpair.push_back (rp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, shared_ptr<AudioTrack>> track_map;
|
||||
/* name -> <channel count, last known index> */
|
||||
std::map<std::string, std::pair<int,int> > tr_multi;
|
||||
|
||||
/* Check for no audio */
|
||||
if (ptf.tracks ().size () == 0) {
|
||||
goto no_audio_tracks;
|
||||
}
|
||||
|
||||
/* Create all PT tracks if not already present and freeze all playlists of tracks we will touch */
|
||||
nth = -1;
|
||||
/* Initialise index sentinels so we can match on .second in the next loop */
|
||||
for (vector<PTFFormat::track_t>::const_iterator a = ptf.tracks ().begin (); a != ptf.tracks ().end (); ++a) {
|
||||
if (a->index != nth) {
|
||||
nth++;
|
||||
if (!(existing_track = dynamic_pointer_cast<AudioTrack> (route_by_name (a->name)))) {
|
||||
/* Create missing track */
|
||||
DEBUG_TRACE (DEBUG::PTImport, string_compose ("Create tr(%1) '%2'\n", nth, a->name));
|
||||
ok = new_audio_routes_tracks_bulk (routes,
|
||||
tracks,
|
||||
1, 2, 0, 1,
|
||||
a->name.c_str (),
|
||||
PresentationInfo::max_order,
|
||||
Normal
|
||||
);
|
||||
if (ok) {
|
||||
existing_track = tracks.back();
|
||||
track_map[a->name] = existing_track;
|
||||
std::shared_ptr<Playlist> playlist = existing_track->playlist();
|
||||
tr_multi[a->name].second = -1;
|
||||
}
|
||||
|
||||
PlaylistState before;
|
||||
before.playlist = playlist;
|
||||
before.before = &playlist->get_state();
|
||||
playlist->clear_changes ();
|
||||
playlist->freeze ();
|
||||
playlists.push_back(before);
|
||||
}
|
||||
/* Count the occurrences of unique indexes with the same track name, these are multichannel tracks */
|
||||
for (vector<PTFFormat::track_t>::const_iterator a = ptf.tracks ().begin (); a != ptf.tracks ().end (); ++a) {
|
||||
if (tr_multi[a->name].second != a->index) {
|
||||
tr_multi[a->name].first++;
|
||||
tr_multi[a->name].second = a->index;
|
||||
}
|
||||
}
|
||||
|
||||
/* Freeze playlists of tracks that already exist in ardour that we will touch */
|
||||
for (vector<PTFFormat::track_t>::const_iterator a = ptf.tracks ().begin (); a != ptf.tracks ().end (); ++a) {
|
||||
if (existing_track = dynamic_pointer_cast<AudioTrack> (route_by_name (a->name))) {
|
||||
if (track_map[a->name] != existing_track) {
|
||||
track_map[a->name] = existing_track;
|
||||
std::shared_ptr<Playlist> playlist = existing_track->playlist();
|
||||
|
||||
PlaylistState before;
|
||||
before.playlist = playlist;
|
||||
before.before = &playlist->get_state();
|
||||
playlist->clear_changes ();
|
||||
playlist->freeze ();
|
||||
playlists.push_back(before);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create all remaining missing PT tracks and freeze playlists of those */
|
||||
for (vector<PTFFormat::track_t>::const_iterator a = ptf.tracks ().begin (); a != ptf.tracks ().end (); ++a) {
|
||||
if (!track_map[a->name]) {
|
||||
|
||||
/* Create missing track */
|
||||
DEBUG_TRACE (DEBUG::PTImport, string_compose ("Create tr(%1) %2ch '%3'\n", tr_multi[a->name].second, tr_multi[a->name].first, a->name));
|
||||
ok = new_audio_routes_tracks_bulk (routes,
|
||||
tracks,
|
||||
tr_multi[a->name].first,
|
||||
std::max (2, tr_multi[a->name].first),
|
||||
0,
|
||||
1,
|
||||
a->name.c_str (),
|
||||
PresentationInfo::max_order,
|
||||
Normal
|
||||
);
|
||||
|
||||
if (ok) {
|
||||
existing_track = tracks.back();
|
||||
|
||||
track_map[a->name] = existing_track;
|
||||
std::shared_ptr<Playlist> playlist = existing_track->playlist();
|
||||
|
||||
PlaylistState before;
|
||||
before.playlist = playlist;
|
||||
before.before = &playlist->get_state();
|
||||
playlist->clear_changes ();
|
||||
playlist->freeze ();
|
||||
playlists.push_back(before);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,32 +404,36 @@ Session::import_pt_rest (PTFFormat& ptf)
|
||||
add_routes (routes, true, true, PresentationInfo::max_order);
|
||||
}
|
||||
|
||||
/* Add regions */
|
||||
/* Add regions (already done) */
|
||||
|
||||
/* Iterate over all pt region -> track entries */
|
||||
for (vector<PTFFormat::track_t>::const_iterator a = ptf.tracks ().begin (); a != ptf.tracks ().end (); ++a) {
|
||||
for (vector<struct ptflookup>::iterator p = ptfregpair.begin ();
|
||||
p != ptfregpair.end (); ++p) {
|
||||
/* Select only one relevant pt track from a multichannel track */
|
||||
if (a->index == tr_multi[a->name].second) {
|
||||
for (vector<Session::PtfLookup>::iterator p = ptfregpair.begin ();
|
||||
p != ptfregpair.end (); ++p) {
|
||||
if (p->index1 == a->reg.index) {
|
||||
|
||||
if (p->index1 == a->reg.index) {
|
||||
/* Matched a ptf active region to an ardour region */
|
||||
std::shared_ptr<Region> r = RegionFactory::region_by_id (p->id);
|
||||
DEBUG_TRACE (DEBUG::PTImport, string_compose ("wav(%1) reg(%2) tr(%3)-%4ch '%5'\n", a->reg.name, a->reg.index, a->index, tr_multi[a->name].first, a->name));
|
||||
|
||||
/* Matched a ptf active region to an ardour region */
|
||||
std::shared_ptr<Region> r = RegionFactory::region_by_id (p->id);
|
||||
DEBUG_TRACE (DEBUG::PTImport, string_compose ("wav(%1) reg(%2) tr(%3) '%4'\n", a->reg.wave.filename, a->reg.index, a->index, a->name));
|
||||
/* Use audio track we know exists */
|
||||
existing_track = track_map[a->name];
|
||||
assert (existing_track);
|
||||
|
||||
/* Use audio track we know exists */
|
||||
existing_track = track_map[a->name];
|
||||
assert (existing_track);
|
||||
/* Put on existing track */
|
||||
std::shared_ptr<Playlist> playlist = existing_track->playlist ();
|
||||
std::shared_ptr<Region> copy (RegionFactory::create (r, true));
|
||||
playlist->clear_changes ();
|
||||
playlist->add_region (copy, timepos_t (a->reg.startpos));
|
||||
//add_command (new StatefulDiffCommand (playlist));
|
||||
|
||||
/* Put on existing track */
|
||||
std::shared_ptr<Playlist> playlist = existing_track->playlist ();
|
||||
std::shared_ptr<Region> copy (RegionFactory::create (r, true));
|
||||
playlist->clear_changes ();
|
||||
playlist->add_region (copy, timepos_t (a->reg.startpos));
|
||||
//add_command (new StatefulDiffCommand (playlist));
|
||||
|
||||
/* Collect latest end of all regions */
|
||||
timepos_t end_of_region = timepos_t (a->reg.startpos + a->reg.length);
|
||||
if (latest < end_of_region) {
|
||||
latest = end_of_region;
|
||||
/* Collect latest end of all regions */
|
||||
timepos_t end_of_region = timepos_t (a->reg.startpos + a->reg.length);
|
||||
if (latest < end_of_region) {
|
||||
latest = end_of_region;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,7 +468,7 @@ no_audio_tracks:
|
||||
std::map <int, std::shared_ptr<MidiTrack> > midi_tracks;
|
||||
/* MIDI - Create unique midi tracks and a lookup table for used tracks */
|
||||
for (vector<midipair>::iterator a = uniquetr.begin (); a != uniquetr.end (); ++a) {
|
||||
struct ptflookup miditr;
|
||||
Session::PtfLookup miditr;
|
||||
list<std::shared_ptr<MidiTrack> > mt (new_midi_track (
|
||||
ChanCount (DataType::MIDI, 1),
|
||||
ChanCount (DataType::MIDI, 1),
|
||||
|
||||
Reference in New Issue
Block a user