2010-01-23 19:44:49 +00:00
|
|
|
/**********************************************************************
|
|
|
|
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
|
|
|
|
Generator.h
|
|
|
|
|
|
|
|
Two Abstract classes, Generator, and BlockGenerator, that effects which
|
2014-06-03 20:30:19 +00:00
|
|
|
generate audio should derive from.
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
Block Generator breaks the synthesis task up into smaller parts.
|
|
|
|
|
|
|
|
Dominic Mazzoni
|
|
|
|
Vaughan Johnson
|
|
|
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
2015-07-03 04:20:21 +00:00
|
|
|
#include "Generator.h"
|
|
|
|
|
2015-06-12 12:03:14 +00:00
|
|
|
#include "../Project.h"
|
2010-01-23 19:44:49 +00:00
|
|
|
#include "../Prefs.h"
|
2019-04-28 10:49:47 +00:00
|
|
|
#include "../ViewInfo.h"
|
2015-07-03 04:20:21 +00:00
|
|
|
#include "../WaveTrack.h"
|
2020-03-04 18:52:10 +00:00
|
|
|
#include "../prefs/TracksBehaviorsPrefs.h"
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
#include "TimeWarper.h"
|
|
|
|
|
2019-05-20 18:27:11 +00:00
|
|
|
#include "../widgets/AudacityMessageBox.h"
|
2015-04-08 18:57:32 +00:00
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
bool Generator::Process()
|
|
|
|
{
|
2015-04-20 00:44:10 +00:00
|
|
|
if (GetDuration() < 0.0)
|
2010-01-23 19:44:49 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
2014-06-03 20:30:19 +00:00
|
|
|
// Set up mOutputTracks.
|
2016-12-31 09:54:52 +00:00
|
|
|
// This effect needs all for sync-lock grouping.
|
|
|
|
this->CopyInputTracks(true);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// Iterate over the tracks
|
|
|
|
bool bGoodResult = true;
|
|
|
|
int ntrack = 0;
|
2014-06-03 20:30:19 +00:00
|
|
|
|
2017-04-11 21:55:19 +00:00
|
|
|
mOutputTracks->Any().VisitWhile( bGoodResult,
|
|
|
|
[&](WaveTrack *track, const Track::Fallthrough &fallthrough) {
|
|
|
|
if (!track->GetSelected())
|
|
|
|
return fallthrough();
|
2020-03-04 18:52:10 +00:00
|
|
|
bool editClipCanMove = GetEditClipsCanMove();
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2010-04-15 21:01:50 +00:00
|
|
|
//if we can't move clips, and we're generating into an empty space,
|
|
|
|
//make sure there's room.
|
|
|
|
if (!editClipCanMove &&
|
2013-02-23 04:33:20 +00:00
|
|
|
track->IsEmpty(mT0, mT1+1.0/track->GetRate()) &&
|
2015-04-20 00:44:10 +00:00
|
|
|
!track->IsEmpty(mT0, mT0+GetDuration()-(mT1-mT0)-1.0/track->GetRate()))
|
2013-02-23 04:33:20 +00:00
|
|
|
{
|
2017-09-10 14:42:33 +00:00
|
|
|
Effect::MessageBox(
|
2019-12-19 19:19:51 +00:00
|
|
|
XO("There is not enough room available to generate the audio"),
|
|
|
|
wxICON_STOP,
|
|
|
|
XO("Error") );
|
2010-01-23 19:44:49 +00:00
|
|
|
Failure();
|
2017-04-11 21:55:19 +00:00
|
|
|
bGoodResult = false;
|
|
|
|
return;
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
2015-04-20 00:44:10 +00:00
|
|
|
if (GetDuration() > 0.0)
|
2010-01-23 19:44:49 +00:00
|
|
|
{
|
2019-05-21 18:38:43 +00:00
|
|
|
auto pProject = FindProject();
|
2010-01-23 19:44:49 +00:00
|
|
|
// Create a temporary track
|
Bug2346: Complete fix...
... without making undesirable dependency cycles.
Eliminate calls to NewWaveTrack in effects, but in Edit>Copy too, which was
not mentioned in the bug report. (Copying a track, deselecting all, and pasting
preserved CLIP colors, but not the TRACK color setting which applies to newly
generated clips.)
Instead, always use the new function WaveTrack::EmptyCopy from the track to be
later replaced, getting color information.
NewWaveTrack is still used in benchmark test, import, the Track menu
commands that make new tracks, recording to new tracks, and generators without
a selection, where there is no track to copy from.
Also when deserializing tracks from the .aup file, in which case the saved
color is later retrieved from the file.
Also, in mix-and-render, where other logic decides whether to copy colors
afterward.
See commit a9658e6ef7f7eaefce4dc37a93d389cca7705f41
2020-03-11 01:40:14 +00:00
|
|
|
auto tmp = track->EmptyCopy();
|
2010-01-23 19:44:49 +00:00
|
|
|
BeforeTrack(*track);
|
2011-12-12 23:43:21 +00:00
|
|
|
BeforeGenerate();
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// Fill it with data
|
2015-04-08 15:22:57 +00:00
|
|
|
if (!GenerateTrack(&*tmp, *track, ntrack))
|
2010-01-23 19:44:49 +00:00
|
|
|
bGoodResult = false;
|
|
|
|
else {
|
|
|
|
// Transfer the data from the temporary track to the actual one
|
|
|
|
tmp->Flush();
|
2021-01-25 17:06:24 +00:00
|
|
|
PasteTimeWarper warper{ mT1, mT0+GetDuration() };
|
2019-05-21 18:38:43 +00:00
|
|
|
const auto &selectedRegion =
|
|
|
|
ViewInfo::Get( *pProject ).selectedRegion;
|
2017-03-22 17:25:55 +00:00
|
|
|
track->ClearAndPaste(
|
2019-03-27 08:15:28 +00:00
|
|
|
selectedRegion.t0(), selectedRegion.t1(),
|
|
|
|
&*tmp, true, false, &warper);
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!bGoodResult) {
|
|
|
|
Failure();
|
2017-04-11 21:55:19 +00:00
|
|
|
return;
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// If the duration is zero, there's no need to actually
|
|
|
|
// generate anything
|
|
|
|
track->Clear(mT0, mT1);
|
|
|
|
}
|
|
|
|
|
|
|
|
ntrack++;
|
2017-04-11 21:55:19 +00:00
|
|
|
},
|
|
|
|
[&](Track *t) {
|
|
|
|
if (t->IsSyncLockSelected()) {
|
|
|
|
t->SyncLockAdjust(mT1, mT0 + GetDuration());
|
|
|
|
}
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
2017-04-11 21:55:19 +00:00
|
|
|
);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2017-04-11 21:55:19 +00:00
|
|
|
if (bGoodResult) {
|
|
|
|
Success();
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2017-04-11 21:55:19 +00:00
|
|
|
this->ReplaceProcessedTracks(bGoodResult);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2017-04-11 21:55:19 +00:00
|
|
|
mT1 = mT0 + GetDuration(); // Update selection.
|
|
|
|
}
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2017-04-11 21:55:19 +00:00
|
|
|
return bGoodResult;
|
2010-01-23 19:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool BlockGenerator::GenerateTrack(WaveTrack *tmp,
|
|
|
|
const WaveTrack &track,
|
|
|
|
int ntrack)
|
|
|
|
{
|
|
|
|
bool bGoodResult = true;
|
2015-04-20 00:44:10 +00:00
|
|
|
numSamples = track.TimeToLongSamples(GetDuration());
|
2016-08-24 15:24:26 +00:00
|
|
|
decltype(numSamples) i = 0;
|
2016-04-14 16:34:59 +00:00
|
|
|
Floats data{ tmp->GetMaxBlockSize() };
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
while ((i < numSamples) && bGoodResult) {
|
2016-08-21 22:05:43 +00:00
|
|
|
const auto block =
|
|
|
|
limitSampleBufferSize( tmp->GetBestBlockSize(i), numSamples - i );
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2016-04-14 16:34:59 +00:00
|
|
|
GenerateBlock(data.get(), track, block);
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
// Add the generated data to the temporary track
|
2016-04-14 16:34:59 +00:00
|
|
|
tmp->Append((samplePtr)data.get(), floatSample, block);
|
2010-01-23 19:44:49 +00:00
|
|
|
i += block;
|
|
|
|
|
|
|
|
// Update the progress meter
|
2016-08-25 12:53:59 +00:00
|
|
|
if (TrackProgress(ntrack,
|
|
|
|
i.as_double() /
|
|
|
|
numSamples.as_double()))
|
2010-01-23 19:44:49 +00:00
|
|
|
bGoodResult = false;
|
|
|
|
}
|
|
|
|
return bGoodResult;
|
|
|
|
}
|