11namespace tracktion {
inline namespace engine
14ExportJob::ExportJob (Edit* edit_,
16 const Project::Ptr& newProject_,
17 const Project::Ptr& srcProject_,
18 TracktionArchiveFile* archive_,
20 bool keepEntireFiles_,
21 TracktionArchiveFile::CompressionType compressionType_,
24 bool includeLibraryFiles_,
26 : ThreadPoolJobWithProgress (
TRANS(
"Exporting") +
"..."),
29 newProject (newProject_),
30 srcProject (srcProject_),
31 handleSize (handleSize_),
32 keepEntireFiles (keepEntireFiles_),
33 compressionType (compressionType_),
35 filesForDeletion (filesForDeletion_),
36 failedFiles (failedFiles_),
37 includeLibraryFiles (includeLibraryFiles_),
38 includeClips (includeClips_)
40 jassert (srcProject !=
nullptr);
41 jassert (newProject !=
nullptr);
44ExportJob::~ExportJob()
56 copyEditFilesToTempDir();
58 copyProjectFilesToTempDir();
60 if (archive !=
nullptr && ! shouldExit())
61 createArchiveFromTempFiles();
65 if (archive !=
nullptr)
68 filesForDeletion.add (archive->getFile());
69 filesForDeletion.add (destDir);
79 return jobHasFinished;
83void ExportJob::copyProjectFilesToTempDir()
85 bool showedSpaceWarning =
false;
88 auto newProjectFile = destDir.getChildFile (srcProject->getProjectFile().getFileName());
90 if (srcProject->getProjectFile().copyFileTo (newProjectFile))
92 newProjectFile.setReadOnly (
false);
94 auto destProject = srcProject->projectManager.createNewProject (newProjectFile);
95 destProject->createNewProjectId();
97 for (
int i = 0; i < destProject->getNumProjectItems(); ++i)
99 progress = ((archive !=
nullptr) ? 0.5f : 1.0f) * i
100 / (
float) destProject->getNumProjectItems();
105 auto srcObject = srcProject->getProjectItemAt (i);
106 auto destObject = destProject->getProjectItemAt (i);
108 if (srcObject !=
nullptr && destObject !=
nullptr
109 && srcObject->getSourceFile().existsAsFile())
111 auto dest = destDir.getChildFile (srcObject->getSourceFile().getFileName())
112 .getNonexistentSibling (
true);
114 auto bytesFree = dest.getBytesFreeOnVolume();
115 auto bytesNeeded =
std::max (2 * srcObject->getSourceFile().getSize(),
119 && bytesFree < bytesNeeded
120 && ! showedSpaceWarning)
122 showedSpaceWarning =
true;
123 edit->engine.getUIBehaviour().showWarningAlert (
TRANS(
"Exporting"),
124 TRANS(
"Disk space is critically low!")
126 +
TRANS(
"Not all files may be exported correctly."));
129 if (! srcObject->getSourceFile().copyFileTo (dest))
131 failedFiles.add (dest.getFileName());
135 dest.setReadOnly (
false);
136 destObject->setSourceFile (dest);
141 callBlocking ([
this, &destProject]()
143 destProject->redirectIDsFromProject (srcProject->getProjectID(), destProject->getProjectID());
149 failedFiles.add (srcProject->getProjectFile().getFullPathName());
154void ExportJob::copyEditFilesToTempDir()
162 for (
int j = t->getClips().size(); --j >= 0;)
164 auto clip = t->getClips().getUnchecked (j);
166 if (clip->type != TrackItem::Type::video
167 && clip->type != TrackItem::Type::marker)
169 clip->removeFromParent();
176 for (
auto s : t->getClipSlotList().getClipSlots())
177 if (auto c = s->getClip())
178 c->removeFromParent();
182 auto allExportables = Exportable::addAllExportables (*edit);
185 handleSize = 10000.0;
187 auto& projectManager = srcProject->projectManager;
188 ReferencedMaterialList refList (projectManager, handleSize);
190 for (
auto exportable : allExportables)
191 for (auto& i : exportable->getReferencedItems())
194 int numThingsCopied = 0;
195 const int totalThingsToCopy = refList.getTotalNumThingsToExport();
197 for (
auto exportable : allExportables)
202 for (
auto ref : exportable->getReferencedItems())
204 progress = ((archive !=
nullptr ? 0.5f : 1.0f) * numThingsCopied) / totalThingsToCopy;
209 double start = 0.0, length = 0.0;
210 auto newFilename = refList.getReassignedFileName (
ref.itemID,
ref.firstTimeUsed,
213 if (length > 0.0 && newFilename.isNotEmpty())
215 auto oldSourceMedia (projectManager.getProjectItem (
ref.itemID));
217 if (oldSourceMedia !=
nullptr
218 && (includeLibraryFiles || ! oldSourceMedia->getProject()->isLibraryProject()))
220 ProjectItem::Ptr newSourceItem;
223 auto newFile = destDir.getChildFile (newFilename);
225 if (! newFile.exists())
229 if (! oldSourceMedia->copySectionToNewFile (newFile, actualNewFile, start, length))
231 failedFiles.add (oldSourceMedia->getFileName());
232 TRACKTION_LOG_ERROR (
"Failed to copy file during edit archive: " + newFile.getFullPathName());
236 newFile = actualNewFile;
238 newSourceItem = newProject->createNewItem (newFile,
239 oldSourceMedia->getType(),
240 oldSourceMedia->getName(),
241 oldSourceMedia->getDescription(),
242 oldSourceMedia->getCategory(),
245 if (newSourceItem !=
nullptr)
246 newSourceItem->copyAllPropertiesFrom (*oldSourceMedia);
253 newSourceItem = newProject->getProjectItemForFile (newFile);
256 auto newID = newSourceItem !=
nullptr ? newSourceItem->getID() : ProjectItemID();
258 callBlocking ([=]() { exportable->reassignReferencedItem (ref, newID, start); });
265 callBlocking ([&]() { exportable->reassignReferencedItem (ref, ProjectItemID::createNewID (newProject->getProjectID()), start); });
271 newProject->moveProjectItem (newProject->getIndexOf (edit->getProjectItemID()), 0);
272 callBlocking ([
this] { EditFileOperations (*edit).save (
true,
true,
false); });
276void ExportJob::createArchiveFromTempFiles()
278 if (archive !=
nullptr && ! shouldExit())
280 if (newProject !=
nullptr)
283 newProject->unlockFile();
288 for (
int i = 0; i < filesForDeletion.size(); ++i)
290 progress = 0.5f + 0.5f * i / filesForDeletion.size();
295 auto compression = TracktionArchiveFile::CompressionType::zip;
296 auto f = filesForDeletion[i];
298 if (AudioFile (srcProject->engine, f).isValid())
299 compression = compressionType;
301 if (! archive->addFile (f, destDir, compression))
302 failedFiles.add (f.getFileName());
305 filesForDeletion.clear();
306 filesForDeletion.add (destDir);
311float ExportJob::getCurrentTaskProgress()
static void JUCE_CALLTYPE disableDenormalisedNumberSupport(bool shouldDisable=true) noexcept
#define TRANS(stringLiteral)
juce::Array< AudioTrack * > getAudioTracks(const Edit &edit)
Returns all the AudioTracks in an Edit.
juce::Array< ClipTrack * > getClipTracks(const Edit &edit)
Returns all the ClipTracks in an Edit.
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.