audacia/src/commands/CompareAudioCommand.cpp
Paul Licameli 13713aab67 Remove nullary overload of AudacityCommand::Apply...
... which by default used GetActiveProject(); do that call instead at a
higher level; so that AudacityCommand.cpp does not depend on Project.cpp.

We lose the override of that for CompareAudioCommand which just did nothing.

But in fact this overload of the base class method could only be used
by EffectUIHost constructed from a command, which never happened: it was only
ever constructed from effects.

This frees two files from dependency cycles
2019-05-18 20:31:17 -04:00

159 lines
4.4 KiB
C++

/**********************************************************************
Audacity - A Digital Audio Editor
Copyright 1999-2018 Audacity Team
License: wxwidgets
Dan Horgan
James Crook
******************************************************************//**
\file CompareAudioCommand.cpp
\brief Contains definitions for CompareAudioCommand class
\class CompareAudioCommand
\brief Returns information about the amount of audio that is about a certain
threshold of difference in two selected tracks
*//*******************************************************************/
#include "../Audacity.h"
#include "CompareAudioCommand.h"
#include "../Project.h"
#include "../WaveTrack.h"
#include <float.h>
#include <wx/intl.h>
#include "../Shuttle.h"
#include "../ShuttleGui.h"
#include "../widgets/ErrorDialog.h"
#include "../widgets/valnum.h"
#include "CommandContext.h"
extern void RegisterCompareAudio( Registrar & R){
R.AddCommand( std::make_unique<CompareAudioCommand>() );
// std::unique_ptr<CommandOutputTargets> &&target
// return std::make_shared<CompareAudioCommand>(*this, std::move(target));
}
bool CompareAudioCommand::DefineParams( ShuttleParams & S ){
S.Define( errorThreshold, wxT("Threshold"), 0.0f, 0.0f, 0.01f, 1.0f );
return true;
}
void CompareAudioCommand::PopulateOrExchange(ShuttleGui & S)
{
S.AddSpace(0, 5);
S.StartMultiColumn(2, wxALIGN_CENTER);
{
S.TieTextBox(_("Threshold:"),errorThreshold);
}
S.EndMultiColumn();
}
// Update member variables with project selection data (and validate)
bool CompareAudioCommand::GetSelection(const CommandContext &context, AudacityProject &proj)
{
// Get the selected time interval
mT0 = proj.mViewInfo.selectedRegion.t0();
mT1 = proj.mViewInfo.selectedRegion.t1();
if (mT0 >= mT1)
{
context.Error(wxT("There is no selection!"));
return false;
}
// Get the selected tracks and check that there are at least two to
// compare
auto trackRange = proj.GetTracks()->Selected< const WaveTrack >();
mTrack0 = *trackRange.first;
if (mTrack0 == NULL)
{
context.Error(wxT("No tracks selected! Select two tracks to compare."));
return false;
}
mTrack1 = * ++ trackRange.first;
if (mTrack1 == NULL)
{
context.Error(wxT("Only one track selected! Select two tracks to compare."));
return false;
}
if ( * ++ trackRange.first )
{
context.Status(wxT("More than two tracks selected - only the first two will be compared."));
}
return true;
}
double CompareAudioCommand::CompareSample(double value1, double value2)
{
return fabs(value1 - value2);
}
inline int min(int a, int b)
{
return (a < b) ? a : b;
}
bool CompareAudioCommand::Apply(const CommandContext & context)
{
if (!GetSelection(context, context.project))
{
return false;
}
wxString msg = wxT("Comparing tracks '");
msg += mTrack0->GetName() + wxT("' and '")
+ mTrack1->GetName() + wxT("'.");
context.Status(msg);
long errorCount = 0;
// Initialize buffers for track data to be analyzed
auto buffSize = std::min(mTrack0->GetMaxBlockSize(), mTrack1->GetMaxBlockSize());
Floats buff0{ buffSize };
Floats buff1{ buffSize };
// Compare tracks block by block
auto s0 = mTrack0->TimeToLongSamples(mT0);
auto s1 = mTrack0->TimeToLongSamples(mT1);
auto position = s0;
auto length = s1 - s0;
while (position < s1)
{
// Get a block of data into the buffers
auto block = limitSampleBufferSize(
mTrack0->GetBestBlockSize(position), s1 - position
);
mTrack0->Get((samplePtr)buff0.get(), floatSample, position, block);
mTrack1->Get((samplePtr)buff1.get(), floatSample, position, block);
for (decltype(block) buffPos = 0; buffPos < block; ++buffPos)
{
if (CompareSample(buff0[buffPos], buff1[buffPos]) > errorThreshold)
{
++errorCount;
}
}
position += block;
context.Progress(
(position - s0).as_double() /
length.as_double()
);
}
// Output the results
double errorSeconds = mTrack0->LongSamplesToTime(errorCount);
context.Status(wxString::Format(wxT("%li"), errorCount));
context.Status(wxString::Format(wxT("%.4f"), errorSeconds));
context.Status(wxString::Format(wxT("Finished comparison: %li samples (%.3f seconds) exceeded the error threshold of %f."), errorCount, errorSeconds, errorThreshold));
return true;
}