11namespace tracktion {
inline namespace engine
14TimeDuration RenderOptions::findEndAllowance (Edit& edit,
19 Plugin::Array plugins;
21 if (tracks !=
nullptr)
22 for (
auto t : allTracks)
23 if (tracks->contains (t->itemID))
24 for (auto p : t->pluginList)
25 plugins.addIfNotAlreadyThere (p);
29 if (auto pl = c->getPluginList())
31 plugins.addIfNotAlreadyThere (p);
33 TimeDuration allowance;
35 for (
auto p : plugins)
37 auto tailLength = p->getTailLength();
42 allowance =
std::max (allowance, TimeDuration::fromSeconds (tailLength));
55static bool isParentTrackSelected (SelectionManager& sm, Track& t)
57 if (
auto ft = t.getParentFolderTrack())
58 return sm.isSelected (ft) || isParentTrackSelected (sm, *ft);
70 if (sm.isSelected (t))
73 if (! t->isPartOfSubmix() && isParentTrackSelected (sm, *t))
83void RenderOptions::loadFromUserSettings()
89 format = (TargetFileFormat)
static_cast<int> (storage.getProperty (SettingID::renderFormat, (
int) wav));
91 if (format != wav || format != aiff)
95 bitDepth = storage.getProperty (SettingID::trackRenderBits, 16);
96 usePlugins = storage.getProperty (SettingID::bypassFilters,
true);
99 markedRegion = storage.getProperty (SettingID::markedRegion,
false);
101 else if (isExportAll())
103 format = (TargetFileFormat)
static_cast<int> (storage.getProperty (SettingID::exportFormat, (
int) wav));
104 selectedClips = storage.getProperty (SettingID::renderOnlySelectedClips,
false);
105 markedRegion = storage.getProperty (SettingID::renderOnlyMarked,
false);
106 normalise = storage.getProperty (SettingID::renderNormalise,
false);
107 adjustBasedOnRMS = storage.getProperty (SettingID::renderRMS,
false);
108 rmsLevelDb = storage.getProperty (SettingID::renderRMSLevelDb, -12.0);
109 peakLevelDb = storage.getProperty (SettingID::renderPeakLevelDb, 0.0);
110 removeSilence = storage.getProperty (SettingID::renderTrimSilence,
false);
111 stereo = storage.getProperty (SettingID::renderStereo,
true);
113 bitDepth = storage.getProperty (SettingID::renderBits, 16);
114 dither = storage.getProperty (SettingID::renderDither,
true);
115 qualityIndex = storage.getProperty (SettingID::quality, 5);
116 addMetadata = storage.getProperty (SettingID::addId3Info,
false);
117 addAcidMetadata = storage.getProperty (SettingID::addAcidMetadata,
false);
118 realTime = storage.getProperty (SettingID::realtime,
false);
119 usePlugins = storage.getProperty (SettingID::passThroughFilters,
true);
121 else if (isEditClipRender())
124 bitDepth = storage.getProperty (SettingID::editClipRenderBits, 16);
125 dither = storage.getProperty (SettingID::editClipRenderDither,
true);
126 realTime = storage.getProperty (SettingID::editClipRealtime,
false);
127 stereo = storage.getProperty (SettingID::editClipRenderStereo,
true);
128 normalise = storage.getProperty (SettingID::editClipRenderNormalise,
false);
129 adjustBasedOnRMS = storage.getProperty (SettingID::editClipRenderRMS,
false);
130 rmsLevelDb = storage.getProperty (SettingID::editClipRenderRMSLevelDb, -12.0);
131 peakLevelDb = storage.getProperty (SettingID::editClipRenderPeakLevelDb, 0.0);
132 usePlugins = storage.getProperty (SettingID::editClipPassThroughFilters,
true);
133 addAcidMetadata = storage.getProperty (SettingID::addAcidMetadata,
false);
138 updateDefaultFilename (
nullptr);
141void RenderOptions::saveToUserSettings()
145 if (isTrackRender() || isClipRender() || isMidiRender())
147 storage.setProperty (SettingID::renderFormat, (
int) format);
148 storage.setProperty (SettingID::trackRenderSampRate, sampleRate.
get());
149 storage.setProperty (SettingID::trackRenderBits, bitDepth.
get());
150 storage.setProperty (SettingID::bypassFilters, usePlugins.
get());
153 storage.setProperty (SettingID::markedRegion, markedRegion.
get());
155 else if (isEditClipRender())
157 storage.setProperty (SettingID::editClipRenderSampRate, sampleRate.
get());
158 storage.setProperty (SettingID::editClipRenderBits, bitDepth.
get());
159 storage.setProperty (SettingID::editClipRenderDither, dither.
get());
160 storage.setProperty (SettingID::editClipRealtime, realTime.
get());
161 storage.setProperty (SettingID::editClipRenderStereo, stereo.
get());
162 storage.setProperty (SettingID::editClipRenderNormalise, normalise.
get());
163 storage.setProperty (SettingID::editClipRenderRMS, adjustBasedOnRMS.
get());
164 storage.setProperty (SettingID::editClipRenderRMSLevelDb, rmsLevelDb.
get());
165 storage.setProperty (SettingID::editClipRenderPeakLevelDb, peakLevelDb.
get());
166 storage.setProperty (SettingID::editClipPassThroughFilters, usePlugins.
get());
167 storage.setProperty (SettingID::addAcidMetadata, addAcidMetadata.
get());
169 else if (isExportAll())
171 storage.setProperty (SettingID::exportFormat, (
int) format);
172 storage.setProperty (SettingID::renderOnlySelectedClips, selectedClips.
get());
173 storage.setProperty (SettingID::renderOnlyMarked, markedRegion.
get());
174 storage.setProperty (SettingID::renderNormalise, normalise.
get());
175 storage.setProperty (SettingID::renderRMS, adjustBasedOnRMS.
get());
176 storage.setProperty (SettingID::renderRMSLevelDb, rmsLevelDb.
get());
177 storage.setProperty (SettingID::renderPeakLevelDb, peakLevelDb.
get());
178 storage.setProperty (SettingID::renderTrimSilence, removeSilence.
get());
179 storage.setProperty (SettingID::renderSampRate, sampleRate.
get());
180 storage.setProperty (SettingID::renderStereo, stereo.
get());
181 storage.setProperty (SettingID::renderBits, bitDepth.
get());
182 storage.setProperty (SettingID::renderDither, dither.
get());
183 storage.setProperty (SettingID::quality, qualityIndex.
get());
184 storage.setProperty (SettingID::addId3Info, addMetadata.
get());
185 storage.setProperty (SettingID::addAcidMetadata, addAcidMetadata.
get());
186 storage.setProperty (SettingID::realtime, realTime.
get());
187 storage.setProperty (SettingID::passThroughFilters, usePlugins.
get());
193 TimeRange timeRangeToRender)
211 p.category = isRender() ? ProjectItem::Category::rendered
212 : ProjectItem::Category::exports;
215 p.allowedClips = allowedClips;
218 p.endAllowance = markedRegion ? 0.0s : 10.0s;
220 if (p.addAcidMetadata)
221 addAcidInfo (edit, p);
223 return (p.audioFormat !=
nullptr || p.createMidiFile)
230 type.
referTo (state, IDs::renderType, um, RenderType::allExport);
231 tracksProperty.
referTo (state, IDs::renderTracks, um, {});
232 createMidiFile.
referTo (state, IDs::renderCreateMidiFile, um,
false);
233 format.referTo (state, IDs::renderFormat, um, wav);
235 stereo.
referTo (state, IDs::renderStereo, um,
true);
237 sampleRate.
referTo (state, IDs::renderSampleRate, um, 44100.0);
238 bitDepth.
referTo (state, IDs::renderBitDepth, um, 32);
239 qualityIndex.
referTo (state, IDs::renderQualityIndex, um, 5);
240 rmsLevelDb.
referTo (state, IDs::renderRMSLevelDb, um, 0.0);
241 peakLevelDb.
referTo (state, IDs::renderPeakLevelDb, um, 0.0);
243 removeSilence.
referTo (state, IDs::renderRemoveSilence, um,
false);
244 normalise.
referTo (state, IDs::renderNormalise, um,
false);
245 dither.
referTo (state, IDs::renderDither, um,
false);
246 adjustBasedOnRMS.
referTo (state, IDs::renderAdjustBasedOnRMS, um,
false);
247 markedRegion.
referTo (state, IDs::renderMarkedRegion, um,
false);
248 selectedTracks.
referTo (state, IDs::renderSelectedTracks, um,
false);
249 selectedClips.
referTo (state, IDs::renderSelectedClips, um,
false);
250 tracksToSeparateFiles.
referTo (state, IDs::renderTracksToSeparateFiles, um,
false);
251 realTime.
referTo (state, IDs::renderRealTime, um,
false);
252 usePlugins.
referTo (state, IDs::renderPlugins, um,
true);
254 addRenderOptions.
referTo (state, IDs::renderOptions, um, none);
255 addRenderToLibrary.
referTo (state, IDs::addRenderToLibrary, um,
false);
256 reverseRender.
referTo (state, IDs::reverseRender, um,
false);
257 addMetadata.
referTo (state, IDs::renderAddMetadata, um,
false);
258 addAcidMetadata.
referTo (state, IDs::addAcidMetadata, um,
false);
261 tracks = EditItemID::parseStringList (tracksProperty);
267 if (v == state && i == IDs::renderTracks)
269 tracks = EditItemID::parseStringList (tracksProperty);
278 auto metadata = edit.getEditMetadata();
280 if (metadata.album.isNotEmpty()) metadataList.
set (
"id3album", metadata.album);
281 if (metadata.artist.isNotEmpty()) metadataList.
set (
"id3artist", metadata.artist);
282 if (metadata.comment.isNotEmpty()) metadataList.
set (
"id3comment", metadata.comment);
283 if (metadata.date.isNotEmpty()) metadataList.
set (
"id3date", metadata.date);
284 if (metadata.genre.isNotEmpty()) metadataList.
set (
"id3genre", metadata.genre);
285 if (metadata.title.isNotEmpty()) metadataList.
set (
"id3title", metadata.title);
286 if (metadata.trackNumber.isNotEmpty()) metadataList.
set (
"id3trackNumber", metadata.trackNumber);
297 TimeRange markedRegionTime)
301 params.destFile = destFile;
302 params.createMidiFile = format == midi;
305 params.bitDepth = bitDepth;
307 params.sampleRateForAudio = sampleRate;
308 params.shouldNormalise = normalise;
309 params.trimSilenceAtEnds = removeSilence;
310 params.shouldNormaliseByRMS = adjustBasedOnRMS;
311 params.normaliseToLevelDb = (
float) (adjustBasedOnRMS ? rmsLevelDb : peakLevelDb);
312 params.canRenderInMono =
true;
313 params.mustRenderInMono = ! stereo;
314 params.usePlugins = (params.createMidiFile || (isTrackRender() || isClipRender() || isEditClipRender())) ? usePlugins :
true;
315 params.useMasterPlugins = isRender() ? false : ((params.createMidiFile || (isEditClipRender())) ? usePlugins :
true);
316 params.realTimeRender = realTime;
317 params.ditheringEnabled = dither;
318 params.quality = qualityIndex;
319 params.category = ProjectItem::Category::rendered;
320 params.separateTracks = tracksToSeparateFiles;
321 params.addAntiDenormalisationNoise = EditPlaybackContext::shouldAddAntiDenormalisationNoise (edit.
engine);
323 if (! isMarkedRegionBigEnough (markedRegionTime))
324 markedRegion =
false;
327 params.time = markedRegionTime;
335 for (
int i = allTracks.size(); --i >= 0;)
336 if (tracks.
contains (allTracks.getUnchecked (i)->itemID))
337 params.tracksToDo.
setBit (i);
339 if (isClipRender() || isMidiRender())
341 params.allowedClips = allowedClips;
342 params.endAllowance = usePlugins ? findEndAllowance (edit, &tracks, &allowedClips) : 0.0s;
343 params.time = params.time.getIntersectionWith (findTimeFromClips (params.allowedClips, params.endAllowance));
346 else if (selectedClips)
348 if (selectionManager !=
nullptr)
350 if (selectionManager->containsType<
Clip>())
352 for (
int i = allTracks.size(); --i >= 0;)
353 if (allTracks.getUnchecked (i)->isAudioTrack())
354 params.tracksToDo.
setBit (i);
356 auto clips = selectionManager->getItemsOfType<
Clip>();
358 for (
auto clip : clips)
359 params.allowedClips.
add (clip);
361 auto time = findTimeFromClips (clips, params.endAllowance);
362 params.time = params.time.getIntersectionWith (
time);
370 else if (selectedTracks)
372 if (selectionManager !=
nullptr)
373 params.tracksToDo = getSelectedTracks (edit, *selectionManager);
378 if (params.tracksToDo.
isZero())
379 params.tracksToDo.
setRange (0, allTracks.size(),
true);
382 params.metadata = getMetadata (edit);
384 params.addAcidMetadata = addAcidMetadata;
393 params.destFile = destFile;
394 params.createMidiFile = format == midi;
397 params.bitDepth = bitDepth;
398 params.blockSizeForAudio = clip.edit.engine.getDeviceManager().getBlockSize();
399 params.sampleRateForAudio = sampleRate;
400 params.shouldNormalise = normalise;
401 params.trimSilenceAtEnds = removeSilence;
402 params.shouldNormaliseByRMS = adjustBasedOnRMS;
403 params.normaliseToLevelDb = (
float) (adjustBasedOnRMS ? rmsLevelDb : peakLevelDb);
404 params.canRenderInMono =
true;
405 params.mustRenderInMono = ! stereo;
406 params.usePlugins = usePlugins;
407 params.useMasterPlugins = usePlugins;
408 params.realTimeRender = realTime;
409 params.ditheringEnabled = dither;
410 params.quality = qualityIndex;
411 params.category = ProjectItem::Category::rendered;
412 params.separateTracks = tracksToSeparateFiles;
413 params.addAntiDenormalisationNoise = EditPlaybackContext::shouldAddAntiDenormalisationNoise (clip.edit.engine);
417 params.time = {
TimePosition(), snapshot->getLength() };
418 params.tracksToDo.setRange (0, snapshot->getNumTracks(),
true);
420 const bool markedBigEnough = snapshot->getMarkIn() < snapshot->getMarkOut() + 0.05s;
422 if (markedRegion && snapshot->areMarksActive() && markedBigEnough)
423 params.time = { snapshot->getMarkIn(), snapshot->getMarkOut() };
431 Renderer::Parameters params (clip.edit);
433 params.destFile = destFile;
434 params.createMidiFile =
format == midi;
437 params.bitDepth = bitDepth;
438 params.blockSizeForAudio = clip.edit.engine.getDeviceManager().getBlockSize();
439 params.sampleRateForAudio = sampleRate;
440 params.endAllowance = endAllowance;
441 params.shouldNormalise = normalise;
442 params.trimSilenceAtEnds = removeSilence;
443 params.shouldNormaliseByRMS = adjustBasedOnRMS;
444 params.normaliseToLevelDb = (
float) (adjustBasedOnRMS ? rmsLevelDb : peakLevelDb);
445 params.canRenderInMono =
true;
446 params.mustRenderInMono = ! stereo;
447 params.usePlugins =
true;
448 params.useMasterPlugins =
false;
449 params.realTimeRender = realTime;
450 params.ditheringEnabled = dither;
451 params.quality = qualityIndex;
452 params.category = ProjectItem::Category::rendered;
453 params.addAntiDenormalisationNoise = EditPlaybackContext::shouldAddAntiDenormalisationNoise (clip.edit.engine);
454 params.time = clip.getEditTimeRange();
455 params.tracksToDo = getTrackIndexes (clip.edit);
456 params.allowedClips = allowedClips;
465 if (format == midi)
return {};
466 if (format == wav)
return afm.getWavFormat();
467 if (format == aiff)
return afm.getAiffFormat();
468 if (format == flac)
return afm.getFlacFormat();
469 if (format == ogg)
return afm.getOggFormat();
475 if (
auto af = afm.getLameFormat())
480 uiNeedsRefresh =
true;
482 return afm.getWavFormat();
494 if (projectItem ==
nullptr || addMode == RenderOptions::none)
497 projectItem->verifyLength();
498 auto trackIndexes = getTrackIndexes (edit);
502 for (
int track = -1;;)
504 track = trackIndexes.findNextSetBit (++track);
509 if (
auto t = alltracks[track])
513 auto lastTrack = tracksArray.
getLast();
515 if (lastTrack ==
nullptr)
523 trackToUse =
dynamic_cast<AudioTrack*
> (lastTrack->getSiblingTrack (1,
false));
526 case thisTrack: [[ fallthrough ]];
528 trackToUse =
dynamic_cast<AudioTrack*
> (lastTrack.get());
531 case addTrack: [[ fallthrough ]];
532 case replaceTrack: [[ fallthrough ]];
533 case none: [[ fallthrough ]];
538 if (trackToUse ==
nullptr)
540 if (selectionManager !=
nullptr)
541 selectionManager->deselectAll();
547 if (trackToUse ==
nullptr)
550 if (addMode == replaceTrack)
551 if (
auto t = tracksArray.
getFirst())
552 trackToUse->setColour (t->getColour());
554 for (
auto t : tracksArray)
558 if (
auto targetTrack = at->getOutput().getDestinationTrack())
559 trackToUse->getOutput().setOutputToTrack (targetTrack);
561 trackToUse->getOutput().setOutputByName (at->getOutput().getOutputName());
567 if (tracksArray.
size() > 1)
568 trackToUse->setName (
TRANS(
"Rendered tracks"));
571 auto startTime = reverseRender ? (
time.getEnd() - TimeDuration::fromSeconds (projectItem->getLength()))
574 const TimeRange insertPos (startTime, startTime + TimeDuration::fromSeconds (projectItem->getLength()));
576 auto newClipName = isTrackRender() ?
TRANS(
"Rendered track")
577 :
TRANS(
"Rendered clip");
581 if (isMidiRender() || format == midi)
583 newClip = trackToUse->insertMIDIClip (newClipName, insertPos,
nullptr);
587 bool allowAutoTempo =
true;
588 bool allowAutoPitch =
true;
590 for (
auto c : allowedClips)
594 if (! ac->getAutoTempo()) allowAutoTempo =
false;
595 if (! ac->getAutoPitch()) allowAutoPitch =
false;
599 allowAutoTempo =
false;
600 allowAutoPitch =
false;
604 newClip = trackToUse->insertWaveClip (newClipName, projectItem->getID(), { insertPos, {} },
false);
613 auto metadata = af.getInfo().metadata;
615 ac->setAutoTempo (allowAutoTempo);
618 if (ac->getLoopInfo().getRootNote() != -1)
619 ac->setAutoPitch (allowAutoPitch);
623 if (newClip ==
nullptr)
629 if (addMode == replaceTrack)
631 for (
auto t : tracksArray)
634 else if (addMode == replaceClips)
638 if (
auto c = allowedClips.
getFirst())
639 if (c->getPosition().time.overlaps (
time))
640 c->getClipTrack()->deleteRegionOfClip (c,
time,
nullptr);
646 if (selectionManager !=
nullptr)
649 newClip->setStart (
time.getStart(),
false,
true);
653 for (
auto c : allowedClips)
654 c->removeFromParent();
661 if (
auto mc =
dynamic_cast<MidiClip*
> (newClip.
get()))
669 MidiList::readSeparateTracksFromFile (projectItem->getSourceFile(), lists, tempoChangeBeatNumbers,
670 bpms, numerators, denominators, length,
false);
673 mc->getSequence().copyFrom (*list,
nullptr);
677 if (selectionManager !=
nullptr)
680 selectionManager->selectOnly (trackToUse.
get());
682 selectionManager->selectOnly (*newClip);
687 acb->setIsReversed (
true);
693void RenderOptions::setToDefault()
695 type = RenderType::allExport;
697 createMidiFile =
false;
700 sampleRate = 44100.0;
707 removeSilence =
false;
710 adjustBasedOnRMS =
false;
711 markedRegion =
false;
712 selectedTracks =
false;
713 selectedClips =
false;
714 tracksToSeparateFiles =
false;
718 addRenderOptions = none;
719 addRenderToLibrary =
false;
720 reverseRender =
false;
723 addAcidMetadata =
false;
726void RenderOptions::updateLastUsedRenderPath (RenderOptions& renderOptions,
const juce::String& itemID)
728 auto& storage = renderOptions.engine.getPropertyStorage();
729 auto lastEditID = storage.getProperty (SettingID::lastEditRender).
toString();
731 if (itemID == lastEditID)
732 renderOptions.destFile = storage.getDefaultLoadSaveDirectory (
"exportRender");
734 storage.setProperty (SettingID::lastEditRender, itemID);
745 ro->tracks.add (t->itemID);
747 ro->addMetadata = getMetadata (edit).
size() != 0;
748 ro->updateDefaultFilename (&edit);
755 AddRenderOptions addOption)
759 auto& edit = first->edit;
763 ro->type = RenderType::track;
764 updateLastUsedRenderPath (*ro, edit.getProjectItemID().toString());
766 for (
auto t : tracks)
767 ro->tracks.add (t->itemID);
769 ro->addRenderOptions = addOption;
770 ro->updateDefaultFilename (&edit);
783 auto& edit = first->edit;
787 updateLastUsedRenderPath (*ro, edit.getProjectItemID().toString());
789 ro->allowedClips = clips;
790 bool areAllClipsMono =
true;
794 if (
auto t = c->getTrack())
798 if (
auto at =
dynamic_cast<AudioTrack*
> (t))
799 if (
auto dest = at->getOutput().getDestinationTrack())
800 ro->tracks.addIfNotAlreadyThere (dest->itemID);
804 if (
auto audioClip =
dynamic_cast<AudioClipBase*
> (c))
806 if (audioClip->getWaveInfo().numChannels > 1)
807 areAllClipsMono =
false;
811 areAllClipsMono =
false;
815 ro->type = midiNotes ? RenderType::midi
818 ro->stereo = ! areAllClipsMono;
819 ro->selectedClips =
false;
820 ro->endAllowance = ro->usePlugins ? findEndAllowance (edit, &ro->tracks, &clips) : TimeDuration();
821 ro->removeSilence = midiNotes;
822 ro->addRenderOptions = nextTrack;
823 ro->updateDefaultFilename (&edit);
835 ro->type = RenderType::editClip;
842RenderOptions::RenderOptions (
Engine& e)
843 : RenderOptions (e,
juce::ValueTree (IDs::RENDER), nullptr)
848 : engine (e), state (s)
851 relinkCachedValues (um);
855 : RenderOptions (other.engine, other.state.createCopy(), um)
859RenderOptions::~RenderOptions()
863 if (! isEditClipRender())
867void RenderOptions::setUINeedsRefresh()
869 uiNeedsRefresh =
true;
874 if (! uiNeedsRefresh)
877 uiNeedsRefresh =
false;
882RenderOptions::TargetFileFormat RenderOptions::setFormat (TargetFileFormat f)
889 if (format == mp3 && afm.getLameFormat() ==
nullptr)
893 updateOptionsForFormat();
898void RenderOptions::setFormatType (
const juce::String& typeString)
902 if (typeString == am.getWavFormat()->getFormatName()) setFormat (wav);
903 else if (typeString == am.getAiffFormat()->getFormatName()) setFormat (aiff);
904 else if (typeString == am.getFlacFormat()->getFormatName()) setFormat (flac);
905 else if (typeString == am.getOggFormat()->getFormatName()) setFormat (ogg);
906 else if (typeString ==
"MP3 file") setFormat (mp3);
907 else if (typeString ==
"MIDI file") setFormat (midi);
908 else setFormat (wav);
911juce::String RenderOptions::getFormatTypeName (TargetFileFormat fmt)
918 case aiff:
return am.getAiffFormat()->getFormatName();
919 case flac:
return am.getFlacFormat()->getFormatName();
920 case ogg:
return am.getOggFormat()->getFormatName();
921 case mp3:
return am.getLameFormat() ==
nullptr ?
juce::String() : am.getLameFormat()->getFormatName();
922 case midi:
return "MIDI file";
923 case numFormats:
return "MIDI file";
933 tracksProperty = EditItemID::listToString (trackIDs);
936HashCode RenderOptions::getTracksHash()
const
938 HashCode tracksHash = 0;
940 for (
auto& t : tracks)
941 tracksHash ^= static_cast<HashCode> (t.getRawID());
946void RenderOptions::setSampleRate (
int sr)
950 auto rates = af->getPossibleSampleRates();
952 if (! rates.contains (sr))
953 sr = rates.contains (44100) ? 44100 : rates[(
int)
std::floor (rates.size() / 2.0)];
965 for (
int i = tracks.
size(); --i >= 0;)
967 res.
setBit (trks.indexOf (t));
972void RenderOptions::setSelected (
bool onlySelectedTrackAndClips)
974 selectedTracks = onlySelectedTrackAndClips;
975 selectedClips = onlySelectedTrackAndClips;
978void RenderOptions::setFilename (
juce::String value,
bool canPromptToOverwriteExisting)
981 auto recentList = engine.
getPropertyStorage().getProperty (SettingID::renderRecentFilesList).toString();
986 #if JUCE_MODAL_LOOPS_PERMITTED
987 if (value.startsWithIgnoreCase (
"$browse"))
999 m.addItem (browse,
TRANS(
"Browse") +
"...");
1000 m.addItem (projectDefault,
TRANS(
"Set to project default"));
1002 int i = recentOffset;
1004 for (
auto& s : recent.getAllFilenames())
1005 m2.addItem (i++, s);
1008 m.addSubMenu (
TRANS(
"Recent"), m2);
1010 auto res = m.show();
1019 if (! chooser.browseForFileToSave (
false))
1022 f = chooser.getResult();
1024 else if (res == projectDefault)
1040 #
if JUCE_MODAL_LOOPS_PERMITTED
1041 && canPromptToOverwriteExisting
1043 TRANS(
"The file you have chosen already exists, do you want to delete it?")
1045 +
TRANS(
"If you choose to cancel, a non existent file name will be chosen automatically.")
1047 +
"(" +
TRANS(
"This operation can't be undone") +
")")
1051 AudioFile (engine, f).deleteFile();
1058 updateDefaultFilename (
nullptr);
1063 auto newRecentList = recent.
toString();
1065 if (recentList != newRecentList)
1066 engine.
getPropertyStorage().setProperty (SettingID::renderRecentFilesList, newRecentList);
1076 formats.
add (am.getWavFormat()->getFormatName());
1077 formats.
add (am.getAiffFormat()->getFormatName());
1081 formats.
add (am.getFlacFormat()->getFormatName());
1082 formats.
add (am.getOggFormat()->getFormatName());
1084 #if JUCE_USE_LAME_AUDIO_FORMAT
1089 formats.
add (am.getLameFormat()->getFormatName());
1092 formats.
add (
"MIDI file");
1100 static const char* renderOptionsText[] = {
NEEDS_TRANS(
"Replace Rendered Tracks"),
1109 renderOptions.add (
TRANS(renderOptionsText[replaceTrack]));
1110 renderOptions.add (
TRANS(renderOptionsText[addTrack]));
1112 if (! isTrackRender())
1114 renderOptions.add (
TRANS(renderOptionsText[nextTrack]));
1115 renderOptions.add (
TRANS(renderOptionsText[thisTrack]));
1116 renderOptions.add (
TRANS(renderOptionsText[replaceClips]));
1117 renderOptions.add (
TRANS(renderOptionsText[none]));
1120 return renderOptions;
1124bool RenderOptions::isMarkedRegionBigEnough (TimeRange region)
1126 return region.getLength() > 0.05s;
1137 return af.getOggFormat()->getQualityOptions();
1139 if (
auto lameFormat = af.getLameFormat())
1141 return lameFormat->getQualityOptions();
1147void RenderOptions::updateHash()
1149 hash = (tracks.
isEmpty() ? 0 : getTracksHash())
1150 ^ (((HashCode) createMidiFile) << 0)
1151 ^ (((HashCode) format) << 1)
1152 ^ (((HashCode) stereo) << 2)
1153 ^ (((HashCode) sampleRate) << 3)
1154 ^ (((HashCode) bitDepth) << 4)
1155 ^ (((HashCode) qualityIndex) << 5)
1156 ^ (((HashCode) removeSilence) << 6)
1157 ^ (((HashCode) normalise) << 7)
1158 ^ (((HashCode) dither) << 8)
1159 ^ (((HashCode) adjustBasedOnRMS) << 9)
1160 ^ ((HashCode) (rmsLevelDb * -4567.2))
1161 ^ ((HashCode) (peakLevelDb * 2453.1))
1162 ^ (((HashCode) markedRegion) << 10)
1163 ^ (((HashCode) selectedTracks) << 12)
1164 ^ (((HashCode) selectedClips) << 12)
1165 ^ (((HashCode) tracksToSeparateFiles) << 13)
1166 ^ (((HashCode) realTime) << 14)
1167 ^ (((HashCode) usePlugins) << 15)
1168 ^ (((HashCode) addMetadata) << 16)
1169 ^ (((HashCode) addAcidMetadata) << 17);
1172void RenderOptions::updateFileName()
1185void RenderOptions::updateOptionsForFormat()
1190 auto rates = af->getPossibleSampleRates();
1193 for (
auto rate : rates)
1194 r.add (
juce::String (rate));
1196 if (! rates.contains ((
int) sampleRate))
1199 if (! rates.contains ((
int) sampleRate))
1200 sampleRate = rates[0];
1204 auto depths = af->getPossibleBitDepths();
1206 for (
auto depth : depths)
1209 if (! depths.contains (bitDepth))
1212 if (! depths.contains (bitDepth))
1213 bitDepth = depths[0];
1216 auto qualities = af->getQualityOptions();
1219 qualityIndex = (
int)
std::ceil (qualities.size() / 2.0);
1226void RenderOptions::updateDefaultFilename (Edit* edit)
1232 const ProjectItem::Category category = isRender() ? ProjectItem::Category::rendered
1233 : ProjectItem::Category::exports;
1236 if (selectedTracks || selectedClips)
1238 if (
auto sm = engine.
getUIBehaviour().getCurrentlyFocusedSelectionManager())
1240 if (
auto clip = sm->getFirstItemOfType<Clip>())
1241 nameStem = clip->getName();
1243 if (
auto track = sm->getFirstItemOfType<Track>())
1244 nameStem = track->getName();
1250 if (edit ==
nullptr)
1253 if (edit !=
nullptr)
1255 nameStem = edit->getName();
1257 if (isTrackRender() && tracks.
size() > 0)
1259 nameStem +=
" " + t->getName();
1261 nameStem +=
" " + (category == ProjectItem::Category::exports ?
TRANS(
"Export")
1262 :
TRANS(
"Render")) +
" 1";
1270 + getCurrentFileExtension());
1272 destFile = getNonExistentSiblingWithIncrementedNumberSuffix (destFile,
false);
1282 return af->getFileExtensions()[0];
ElementType getUnchecked(int index) const
bool isEmpty() const noexcept
int size() const noexcept
ElementType getFirst() const noexcept
void add(const ElementType &newElement)
bool contains(ParameterType elementToLookFor) const
bool addIfNotAlreadyThere(ParameterType newElement)
BigInteger & setRange(int startBit, int numBits, bool shouldBeSet)
bool isZero() const noexcept
BigInteger & setBit(int bitNumber)
void referTo(ValueTree &tree, const Identifier &property, UndoManager *um)
Type get() const noexcept
String getFileExtension() const
bool existsAsFile() const
const String & getFullPathName() const noexcept
File getChildFile(StringRef relativeOrAbsolutePath) const
File getParentDirectory() const
File withFileExtension(StringRef newExtension) const
static String createLegalFileName(const String &fileNameToFix)
const String & toString() const noexcept
ObjectClass * getFirst() const noexcept
void restoreFromString(const String &stringifiedVersion)
void addFile(const File &file)
const StringArray & getAllFilenames() const noexcept
int size() const noexcept
ObjectClassPtr getFirst() const noexcept
ObjectClassPtr getLast() const noexcept
ObjectClass * add(ObjectClass *newObject)
ReferencedType * get() const noexcept
void add(String stringToAdd)
void set(const String &key, const String &value)
int size() const noexcept
bool isEmpty() const noexcept
void addListener(Listener *listener)
void removeListener(Listener *listener)
Base class for Clips that produce some kind of audio e.g.
This is the main source of an Edit clip and is responsible for managing its properties.
static Ptr getOrCreateRenderJob(Engine &, Renderer::Parameters &, bool deleteEdit, bool silenceOnBackup, bool reverse)
Returns a job that will have been started to generate the Render described by the params.
The Tracktion Edit class!
void deleteTrack(Track *)
Deletes a Track.
TimeDuration getLength() const
Returns the end time of last clip.
juce::ReferenceCountedObjectPtr< AudioTrack > insertNewAudioTrack(TrackInsertPoint, SelectionManager *)
Inserts a new AudioTrack in the Edit.
ProjectItemID getProjectItemID() const noexcept
Returns the ProjectItemID of the Edit.
Engine & engine
A reference to the Engine.
PropertyStorage & getPropertyStorage() const
Returns the PropertyStorage user settings customisable XML file.
AudioFileFormatManager & getAudioFileFormatManager() const
Returns the AudioFileFormatManager that maintains a list of available audio file formats.
UIBehaviour & getUIBehaviour() const
Returns the UIBehaviour class.
DeviceManager & getDeviceManager() const
Returns the DeviceManager instance for handling audio / MIDI devices.
static bool lameIsAvailable()
Returns true if a valid LAME/FFmpeg file is found.
static void registerAudioFormat(AudioFileFormatManager &)
Add the LAMEAudioFormat to the AudioFileFormatManager.
Represents a set of user properties used to control a render operation, using a ValueTree to hold the...
static std::unique_ptr< RenderOptions > forGeneralExporter(Edit &)
Creates a default RenderOptions object for a general purpose exporter.
juce::AudioFormat * getAudioFormat()
Returns an AudioFormat to use for the current render properties.
AddRenderOptions
Enum to set the options for renders.
bool getUINeedsRefresh()
If you've chnaged a property that will cause the UI configuration to change this will return true whi...
RenderManager::Job::Ptr performBackgroundRender(Edit &, SelectionManager *, TimeRange timeRangeToRender)
Performs the render operation on a background thread.
Renderer::Parameters getRenderParameters(Edit &, SelectionManager *, TimeRange markedRegion)
Returns a set of renderer parameters which can be used to describe a render operation.
Clip::Ptr applyRenderToEdit(Edit &, ProjectItem::Ptr, TimeRange time, SelectionManager *) const
Adds the given ProjectItem to the Edit using the render properties for positioning info.
Manages a list of items that are currently selected.
virtual bool showOkCancelAlertBox(const juce::String &title, const juce::String &message, const juce::String &ok={}, const juce::String &cancel={})
Should display a dismissable alert window.
An audio clip that uses an audio file as its source.
#define TRANS(stringLiteral)
#define NEEDS_TRANS(stringLiteral)
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
@ no
Don't move up subsequent track content.
juce::Array< Track * > getAllTracks(const Edit &edit)
Returns all the tracks in an Edit.
void deleteRegionOfSelectedClips(SelectionManager &selectionManager, TimeRange rangeToDelete, CloseGap closeGap, bool moveAllSubsequentClipsOnTrack)
Deletes a time range of a Clip selection, optionally closing the gap.
Track * findTrackForID(const Edit &edit, EditItemID id)
Returns the Track with a given ID if contained in the Edit.
TimeRange findUnionOfEditTimeRanges(const ArrayType &items)
Returns the the time range that covers all the given TrackItems.
RangeType< TimePosition > TimeRange
A RangeType based on real time (i.e.
Represents a duration in beats.
Represents a position in real-life time.
Defines the place to insert Track[s].
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.