/********************************************************************** Audacity - A Digital Audio Editor Copyright 1999-2009 Audacity Team License: wxwidgets Dan Horgan ******************************************************************//** \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 "CompareAudioCommand.h" #include "../Project.h" #include "Command.h" wxString CompareAudioCommandType::BuildName() { return wxT("CompareAudio"); } void CompareAudioCommandType::BuildSignature(CommandSignature &signature) { DoubleValidator *thresholdValidator = new DoubleValidator(); signature.AddParameter(wxT("Threshold"), 0.0, thresholdValidator); } Command *CompareAudioCommandType::Create(CommandOutputTarget *target) { return new CompareAudioCommand(*this, target); } // Update member variables with project selection data (and validate) bool CompareAudioCommand::GetSelection(AudacityProject &proj) { // Get the selected time interval mT0 = proj.mViewInfo.sel0; mT1 = proj.mViewInfo.sel1; if (mT0 >= mT1) { Error(wxT("There is no selection!")); return false; } // Get the selected tracks and check that there are at least two to // compare SelectedTrackListOfKindIterator iter(Track::Wave, proj.GetTracks()); mTrack0 = (WaveTrack*)(iter.First()); if (mTrack0 == NULL) { Error(wxT("No tracks selected! Select two tracks to compare.")); return false; } mTrack1 = (WaveTrack*)(iter.Next()); if (mTrack1 == NULL) { Error(wxT("Only one track selected! Select two tracks to compare.")); return false; } if (iter.Next() != NULL) { 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(CommandExecutionContext context) { if (!GetSelection(*context.proj)) { return false; } wxString msg = wxT("Comparing tracks '"); msg += mTrack0->GetName() + wxT("' and '") + mTrack1->GetName() + wxT("'."); Status(msg); long errorCount = 0; double errorThreshold = GetDouble(wxT("Threshold")); // Initialize buffers for track data to be analyzed int buffSize = min(mTrack0->GetMaxBlockSize(), mTrack1->GetMaxBlockSize()); float *buff0 = new float[buffSize]; float *buff1 = new float[buffSize]; // Compare tracks block by block long s0 = mTrack0->TimeToLongSamples(mT0); long s1 = mTrack0->TimeToLongSamples(mT1); long position = s0; long length = s1 - s0; while (position < s1) { // Get a block of data into the buffers sampleCount block = mTrack0->GetBestBlockSize(position); if (position + block > s1) { block = s1 - position; } mTrack0->Get((samplePtr)buff0, floatSample, position, block); mTrack1->Get((samplePtr)buff1, floatSample, position, block); int buffPos = 0; for (buffPos = 0; buffPos < block; ++buffPos) { if (CompareSample(buff0[buffPos], buff1[buffPos]) > errorThreshold) { ++errorCount; } } position += block; Progress((position - mT0) / length); } delete [] buff0; delete [] buff1; // Output the results double errorSeconds = mTrack0->LongSamplesToTime(errorCount); Status(wxString::Format(wxT("%i"), errorCount)); Status(wxString::Format(wxT("%.4f"), errorSeconds)); Status(wxString::Format(wxT("Finished comparison: %i samples (%.3f seconds) exceeded the error threshold of %f."), errorCount, errorSeconds, errorThreshold)); return true; } // Indentation settings for Vim and Emacs and unique identifier for Arch, a // version control system. Please do not modify past this point. // // Local Variables: // c-basic-offset: 3 // indent-tabs-mode: nil // End: // // vim: et sts=3 sw=3 // arch-tag: TBD