diff --git a/src/Audacity.h b/src/Audacity.h
index c5ea7591d..c5ff40e1e 100644
--- a/src/Audacity.h
+++ b/src/Audacity.h
@@ -175,7 +175,7 @@ void QuitAudacity();
 #define LINEAR_TO_DB(x) (20.0 * log10(x))
 
 #define MAX_AUDIO (1. - 1./(1<<15))
-#define JUST_BELOW_MAX_AUDIO (1. - 1./(1<<14))
+#define JUST_BELOW_MAX_AUDIO (1.f - 1.f/(1<<14))
 
 // Marks strings for extraction only...must use wxGetTranslation() to translate.
 #define XO(s) wxT(s)
diff --git a/src/BlockFile.cpp b/src/BlockFile.cpp
index db43cfc26..01c9d9f8b 100644
--- a/src/BlockFile.cpp
+++ b/src/BlockFile.cpp
@@ -371,14 +371,8 @@ void BlockFile::FixSummary(void *data)
 ///
 /// @param start The offset in this block where the region should begin
 /// @param len   The number of samples to include in the region
-/// @param *outMin A pointer to where the minimum value for this region
-///                should be stored
-/// @param *outMax A pointer to where the maximum value for this region
-///                should be stored
-/// @param *outRMS A pointer to where the maximum RMS value for this
-///                region should be stored.
-void BlockFile::GetMinMax(size_t start, size_t len,
-                  float *outMin, float *outMax, float *outRMS) const
+auto BlockFile::GetMinMaxRMS(size_t start, size_t len, bool mayThrow)
+   const -> MinMaxRMS
 {
    // TODO: actually use summaries
    SampleBuffer blockData(len, floatSample);
@@ -399,26 +393,16 @@ void BlockFile::GetMinMax(size_t start, size_t len,
       sumsq += (sample*sample);
    }
 
-   *outMin = min;
-   *outMax = max;
-   *outRMS = sqrt(sumsq/len);
+   return { min, max, (float)sqrt(sumsq/len) };
 }
 
 /// Retrieves the minimum, maximum, and maximum RMS of this entire
 /// block.  This is faster than the other GetMinMax function since
 /// these values are already computed.
-///
-/// @param *outMin A pointer to where the minimum value for this block
-///                should be stored
-/// @param *outMax A pointer to where the maximum value for this block
-///                should be stored
-/// @param *outRMS A pointer to where the maximum RMS value for this
-///                block should be stored.
-void BlockFile::GetMinMax(float *outMin, float *outMax, float *outRMS) const
+auto BlockFile::GetMinMaxRMS(bool)
+   const -> MinMaxRMS
 {
-   *outMin = mMin;
-   *outMax = mMax;
-   *outRMS = mRMS;
+   return { mMin, mMax, mRMS };
 }
 
 /// Retrieves a portion of the 256-byte summary buffer from this BlockFile.  This
diff --git a/src/BlockFile.h b/src/BlockFile.h
index 8e9813a62..56a6cf123 100644
--- a/src/BlockFile.h
+++ b/src/BlockFile.h
@@ -117,11 +117,13 @@ class PROFILE_DLL_API BlockFile /* not final, abstract */ {
    /// Returns TRUE if this BlockFile is locked
    virtual bool IsLocked();
 
+   struct MinMaxRMS { float min, max, RMS; };
+
    /// Gets extreme values for the specified region
-   virtual void GetMinMax(size_t start, size_t len,
-                          float *outMin, float *outMax, float *outRMS) const;
+   virtual MinMaxRMS GetMinMaxRMS(size_t start, size_t len,
+                          bool mayThrow = true) const;
    /// Gets extreme values for the entire block
-   virtual void GetMinMax(float *outMin, float *outMax, float *outRMS) const;
+   virtual MinMaxRMS GetMinMaxRMS(bool mayThrow = true) const;
    /// Returns the 256 byte summary data block
    virtual bool Read256(float *buffer, size_t start, size_t len);
    /// Returns the 64K summary data block
diff --git a/src/Sequence.cpp b/src/Sequence.cpp
index 465edb0be..ce5641a38 100644
--- a/src/Sequence.cpp
+++ b/src/Sequence.cpp
@@ -225,13 +225,17 @@ bool Sequence::ConvertToSampleFormat(sampleFormat format, bool* pbChanged)
    return bSuccess;
 }
 
-bool Sequence::GetMinMax(sampleCount start, sampleCount len,
-                         float * outMin, float * outMax) const
+std::pair<float, float> Sequence::GetMinMax(
+   sampleCount start, sampleCount len, bool mayThrow) const
 {
    if (len == 0 || mBlock.size() == 0) {
-      *outMin = float(0.0);   // FLT_MAX?  So it doesn't look like a spurious '0' to a caller?
-      *outMax = float(0.0);   // -FLT_MAX?  So it doesn't look like a spurious '0' to a caller?
-      return true;
+      return {
+         0.f,
+         // FLT_MAX?  So it doesn't look like a spurious '0' to a caller?
+
+         0.f
+         // -FLT_MAX?  So it doesn't look like a spurious '0' to a caller?
+      };
    }
 
    float min = FLT_MAX;
@@ -245,13 +249,12 @@ bool Sequence::GetMinMax(sampleCount start, sampleCount len,
    // already in memory.
 
    for (unsigned b = block0 + 1; b < block1; ++b) {
-      float blockMin, blockMax, blockRMS;
-      mBlock[b].f->GetMinMax(&blockMin, &blockMax, &blockRMS);
+      auto results = mBlock[b].f->GetMinMaxRMS(mayThrow);
 
-      if (blockMin < min)
-         min = blockMin;
-      if (blockMax > max)
-         max = blockMax;
+      if (results.min < min)
+         min = results.min;
+      if (results.max > max)
+         max = results.max;
    }
 
    // Now we take the first and last blocks into account, noting that the
@@ -259,12 +262,11 @@ bool Sequence::GetMinMax(sampleCount start, sampleCount len,
    // of either of these blocks is within min...max, then we can ignore them.
    // If not, we need read some samples and summaries from disk.
    {
-      float block0Min, block0Max, block0RMS;
       const SeqBlock &theBlock = mBlock[block0];
       const auto &theFile = theBlock.f;
-      theFile->GetMinMax(&block0Min, &block0Max, &block0RMS);
+      auto results = theFile->GetMinMaxRMS(mayThrow);
 
-      if (block0Min < min || block0Max > max) {
+      if (results.min < min || results.max > max) {
          // start lies within theBlock:
          auto s0 = ( start - theBlock.start ).as_size_t();
          const auto maxl0 = (
@@ -274,54 +276,43 @@ bool Sequence::GetMinMax(sampleCount start, sampleCount len,
          wxASSERT(maxl0 <= mMaxSamples); // Vaughan, 2011-10-19
          const auto l0 = limitSampleBufferSize ( maxl0, len );
 
-         float partialMin, partialMax, partialRMS;
-         theFile->GetMinMax(s0, l0,
-            &partialMin, &partialMax, &partialRMS);
-         if (partialMin < min)
-            min = partialMin;
-         if (partialMax > max)
-            max = partialMax;
+         results = theFile->GetMinMaxRMS(s0, l0, mayThrow);
+         if (results.min < min)
+            min = results.min;
+         if (results.max > max)
+            max = results.max;
       }
    }
 
    if (block1 > block0)
    {
-      float block1Min, block1Max, block1RMS;
       const SeqBlock &theBlock = mBlock[block1];
       const auto &theFile = theBlock.f;
-      theFile->GetMinMax(&block1Min, &block1Max, &block1RMS);
+      auto results = theFile->GetMinMaxRMS(mayThrow);
 
-      if (block1Min < min || block1Max > max) {
+      if (results.min < min || results.max > max) {
 
          // start + len - 1 lies in theBlock:
          const auto l0 = ( start + len - theBlock.start ).as_size_t();
          wxASSERT(l0 <= mMaxSamples); // Vaughan, 2011-10-19
 
-         float partialMin, partialMax, partialRMS;
-         theFile->GetMinMax(0, l0,
-            &partialMin, &partialMax, &partialRMS);
-         if (partialMin < min)
-            min = partialMin;
-         if (partialMax > max)
-            max = partialMax;
+         results = theFile->GetMinMaxRMS(0, l0, mayThrow);
+         if (results.min < min)
+            min = results.min;
+         if (results.max > max)
+            max = results.max;
       }
    }
 
-   *outMin = min;
-   *outMax = max;
-
-   return true;
+   return { min, max };
 }
 
-bool Sequence::GetRMS(sampleCount start, sampleCount len,
-                         float * outRMS) const
+float Sequence::GetRMS(sampleCount start, sampleCount len, bool mayThrow) const
 {
    // len is the number of samples that we want the rms of.
    // it may be longer than a block, and the code is carefully set up to handle that.
-   if (len == 0 || mBlock.size() == 0) {
-      *outRMS = float(0.0);
-      return true;
-   }
+   if (len == 0 || mBlock.size() == 0)
+      return 0.f;
 
    double sumsq = 0.0;
    sampleCount length = 0; // this is the cumulative length of the bits we have the ms of so far, and should end up == len
@@ -333,12 +324,12 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len,
    // this is very fast because we have the rms of every entire block
    // already in memory.
    for (unsigned b = block0 + 1; b < block1; b++) {
-      float blockMin, blockMax, blockRMS;
       const SeqBlock &theBlock = mBlock[b];
       const auto &theFile = theBlock.f;
-      theFile->GetMinMax(&blockMin, &blockMax, &blockRMS);
+      auto results = theFile->GetMinMaxRMS(mayThrow);
 
       const auto fileLen = theFile->GetLength();
+      const auto blockRMS = results.RMS;
       sumsq += blockRMS * blockRMS * fileLen;
       length += fileLen;
    }
@@ -357,9 +348,8 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len,
       wxASSERT(maxl0 <= mMaxSamples); // Vaughan, 2011-10-19
       const auto l0 = limitSampleBufferSize( maxl0, len );
 
-      float partialMin, partialMax, partialRMS;
-      theFile->GetMinMax(s0, l0, &partialMin, &partialMax, &partialRMS);
-
+      auto results = theFile->GetMinMaxRMS(s0, l0, mayThrow);
+      const auto partialRMS = results.RMS;
       sumsq += partialRMS * partialRMS * l0;
       length += l0;
    }
@@ -372,8 +362,8 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len,
       const auto l0 = ( start + len - theBlock.start ).as_size_t();
       wxASSERT(l0 <= mMaxSamples); // PRL: I think Vaughan missed this
 
-      float partialMin, partialMax, partialRMS;
-      theFile->GetMinMax(0, l0, &partialMin, &partialMax, &partialRMS);
+      auto results = theFile->GetMinMaxRMS(0, l0, mayThrow);
+      const auto partialRMS = results.RMS;
       sumsq += partialRMS * partialRMS * l0;
       length += l0;
    }
@@ -381,9 +371,7 @@ bool Sequence::GetRMS(sampleCount start, sampleCount len,
    // PRL: catch bugs like 1320:
    wxASSERT(length == len);
 
-   *outRMS = sqrt(sumsq / length.as_double() );
-
-   return true;
+   return sqrt(sumsq / length.as_double() );
 }
 
 std::unique_ptr<Sequence> Sequence::Copy(sampleCount s0, sampleCount s1) const
diff --git a/src/Sequence.h b/src/Sequence.h
index 278a1082b..3095e2c67 100644
--- a/src/Sequence.h
+++ b/src/Sequence.h
@@ -169,10 +169,9 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{
    // Retrieving summary info
    //
 
-   bool GetMinMax(sampleCount start, sampleCount len,
-                  float * min, float * max) const;
-   bool GetRMS(sampleCount start, sampleCount len,
-                  float * outRMS) const;
+   std::pair<float, float> GetMinMax(
+      sampleCount start, sampleCount len, bool mayThrow) const;
+   float GetRMS(sampleCount start, sampleCount len, bool mayThrow) const;
 
    //
    // Getting block size and alignment information
diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp
index ecad3e6d7..33779c360 100644
--- a/src/WaveClip.cpp
+++ b/src/WaveClip.cpp
@@ -36,6 +36,8 @@
 #include "WaveTrack.h"
 #include "FFT.h"
 #include "Profiler.h"
+#include "InconsistencyException.h"
+#include "UserException.h"
 
 #include "prefs/SpectrogramSettings.h"
 
@@ -1284,43 +1286,48 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
    return true;
 }
 
-bool WaveClip::GetMinMax(float *min, float *max,
-                          double t0, double t1) const
+std::pair<float, float> WaveClip::GetMinMax(
+   double t0, double t1, bool mayThrow) const
 {
-   *min = float(0.0);   // harmless, but unused since Sequence::GetMinMax does not use these values
-   *max = float(0.0);   // harmless, but unused since Sequence::GetMinMax does not use these values
-
-   if (t0 > t1)
-      return false;
+   if (t0 > t1) {
+      if (mayThrow)
+         //THROW_INCONSISTENCY_EXCEPTION
+         ;
+      return {
+         0.f,  // harmless, but unused since Sequence::GetMinMax does not use these values
+         0.f   // harmless, but unused since Sequence::GetMinMax does not use these values
+      };
+   }
 
    if (t0 == t1)
-      return true;
+      return{ 0.f, 0.f };
 
    sampleCount s0, s1;
 
    TimeToSamplesClip(t0, &s0);
    TimeToSamplesClip(t1, &s1);
 
-   return mSequence->GetMinMax(s0, s1-s0, min, max);
+   return mSequence->GetMinMax(s0, s1-s0, mayThrow);
 }
 
-bool WaveClip::GetRMS(float *rms, double t0,
-                          double t1)
+float WaveClip::GetRMS(double t0, double t1, bool mayThrow) const
 {
-   *rms = float(0.0);
-
-   if (t0 > t1)
-      return false;
+   if (t0 > t1) {
+      if (mayThrow)
+         //THROW_INCONSISTENCY_EXCEPTION
+         ;
+      return 0.f;
+   }
 
    if (t0 == t1)
-      return true;
+      return 0.f;
 
    sampleCount s0, s1;
 
    TimeToSamplesClip(t0, &s0);
    TimeToSamplesClip(t1, &s1);
 
-   return mSequence->GetRMS(s0, s1-s0, rms);
+   return mSequence->GetRMS(s0, s1-s0, mayThrow);
 }
 
 void WaveClip::ConvertToSampleFormat(sampleFormat format)
diff --git a/src/WaveClip.h b/src/WaveClip.h
index 7800dd27b..ed0727d1e 100644
--- a/src/WaveClip.h
+++ b/src/WaveClip.h
@@ -278,8 +278,9 @@ public:
                        const sampleCount *& where,
                        size_t numPixels,
                        double t0, double pixelsPerSecond) const;
-   bool GetMinMax(float *min, float *max, double t0, double t1) const;
-   bool GetRMS(float *rms, double t0, double t1);
+   std::pair<float, float> GetMinMax(
+      double t0, double t1, bool mayThrow = true) const;
+   float GetRMS(double t0, double t1, bool mayThrow = true) const;
 
    // Set/clear/get rectangle that this WaveClip fills on screen. This is
    // called by TrackArtist while actually drawing the tracks and clips.
diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp
index 01ae05eab..9523dbc83 100644
--- a/src/WaveTrack.cpp
+++ b/src/WaveTrack.cpp
@@ -55,6 +55,8 @@ Track classes.
 #include "prefs/SpectrumPrefs.h"
 #include "prefs/WaveformPrefs.h"
 
+#include "InconsistencyException.h"
+
 #include "Experimental.h"
 
 using std::max;
@@ -1902,61 +1904,58 @@ double WaveTrack::GetEndTime() const
 // expressed relative to t=0.0 at the track's sample rate.
 //
 
-bool WaveTrack::GetMinMax(float *min, float *max,
-                          double t0, double t1) const
+std::pair<float, float> WaveTrack::GetMinMax(
+   double t0, double t1, bool mayThrow) const
 {
+   std::pair<float, float> results {
+      // we need these at extremes to make sure we find true min and max
+      FLT_MAX, -FLT_MAX
+   };
    bool clipFound = false;
 
-   *min = FLT_MAX;   // we need these at extremes to make sure we find true min and max
-   *max = -FLT_MAX;
-
-   if (t0 > t1)
-      return false;
+   if (t0 > t1) {
+      if (mayThrow)
+         //THROW_INCONSISTENCY_EXCEPTION
+         ;
+      return results;
+   }
 
    if (t0 == t1)
-      return true;
-
-   bool result = true;
+      return results;
 
    for (const auto &clip: mClips)
    {
       if (t1 >= clip->GetStartTime() && t0 <= clip->GetEndTime())
       {
          clipFound = true;
-         float clipmin, clipmax;
-         if (clip->GetMinMax(&clipmin, &clipmax, t0, t1))
-         {
-            if (clipmin < *min)
-               *min = clipmin;
-            if (clipmax > *max)
-               *max = clipmax;
-         } else
-         {
-            result = false;
-         }
+         auto clipResults = clip->GetMinMax(t0, t1, mayThrow);
+         if (clipResults.first < results.first)
+            results.first = clipResults.first;
+         if (clipResults.second > results.second)
+            results.second = clipResults.second;
       }
    }
 
    if(!clipFound)
    {
-      *min = float(0.0);   // sensible defaults if no clips found
-      *max = float(0.0);
+      results = { 0.f, 0.f }; // sensible defaults if no clips found
    }
 
-   return result;
+   return results;
 }
 
-bool WaveTrack::GetRMS(float *rms, double t0, double t1) const
+float WaveTrack::GetRMS(double t0, double t1, bool mayThrow) const
 {
-   *rms = float(0.0);
-
-   if (t0 > t1)
-      return false;
+   if (t0 > t1) {
+      if (mayThrow)
+         //THROW_INCONSISTENCY_EXCEPTION
+         ;
+      return 0.f;
+   }
 
    if (t0 == t1)
-      return true;
+      return 0.f;
 
-   bool result = true;
    double sumsq = 0.0;
    sampleCount length = 0;
 
@@ -1967,25 +1966,17 @@ bool WaveTrack::GetRMS(float *rms, double t0, double t1) const
       // if (t1 >= clip->GetStartTime() && t0 <= clip->GetEndTime())
       if (t1 >= clip->GetStartTime() && t0 <= clip->GetEndTime())
       {
-         float cliprms;
          sampleCount clipStart, clipEnd;
 
-         if (clip->GetRMS(&cliprms, t0, t1))
-         {
-            clip->TimeToSamplesClip(wxMax(t0, clip->GetStartTime()), &clipStart);
-            clip->TimeToSamplesClip(wxMin(t1, clip->GetEndTime()), &clipEnd);
-            sumsq += cliprms * cliprms * (clipEnd - clipStart).as_float();
-            length += (clipEnd - clipStart);
-         }
-         else
-         {
-            result = false;
-         }
+         float cliprms = clip->GetRMS(t0, t1, mayThrow);
+
+         clip->TimeToSamplesClip(wxMax(t0, clip->GetStartTime()), &clipStart);
+         clip->TimeToSamplesClip(wxMin(t1, clip->GetEndTime()), &clipEnd);
+         sumsq += cliprms * cliprms * (clipEnd - clipStart).as_float();
+         length += (clipEnd - clipStart);
       }
    }
-   *rms = length > 0 ? sqrt(sumsq / length.as_double()) : 0.0;
-
-   return result;
+   return length > 0 ? sqrt(sumsq / length.as_double()) : 0.0;
 }
 
 bool WaveTrack::Get(samplePtr buffer, sampleFormat format,
diff --git a/src/WaveTrack.h b/src/WaveTrack.h
index 15daad1b1..68c2d3607 100644
--- a/src/WaveTrack.h
+++ b/src/WaveTrack.h
@@ -257,9 +257,9 @@ class AUDACITY_DLL_API WaveTrack final : public Track {
                    sampleCount start, size_t len);
    void GetEnvelopeValues(double *buffer, size_t bufferLen,
                          double t0) const;
-   bool GetMinMax(float *min, float *max,
-                  double t0, double t1) const;
-   bool GetRMS(float *rms, double t0, double t1) const;
+   std::pair<float, float> GetMinMax(
+      double t0, double t1, bool mayThrow = true) const;
+   float GetRMS(double t0, double t1, bool mayThrow = true) const;
 
    //
    // MM: We now have more than one sequence and envelope per track, so
diff --git a/src/blockfile/ODDecodeBlockFile.cpp b/src/blockfile/ODDecodeBlockFile.cpp
index e5c0f3681..c6dff23dd 100644
--- a/src/blockfile/ODDecodeBlockFile.cpp
+++ b/src/blockfile/ODDecodeBlockFile.cpp
@@ -29,6 +29,7 @@ The summary is eventually computed and written to a file in a background thread.
 
 #include "../FileFormats.h"
 #include "../Internat.h"
+#include "NotYetAvailableException.h"
 
 const int bheaderTagLen = 20;
 char bheaderTag[bheaderTagLen + 1] = "AudacityBlockFile112";
@@ -91,37 +92,45 @@ auto ODDecodeBlockFile::GetSpaceUsage() const -> DiskByteCount
 
 
 /// Gets extreme values for the specified region
-void ODDecodeBlockFile::GetMinMax(size_t start, size_t len,
-                          float *outMin, float *outMax, float *outRMS) const
+auto ODDecodeBlockFile::GetMinMaxRMS(
+   size_t start, size_t len, bool mayThrow) const -> MinMaxRMS
 {
    if(IsSummaryAvailable())
    {
-      SimpleBlockFile::GetMinMax(start,len,outMin,outMax,outRMS);
+      return SimpleBlockFile::GetMinMaxRMS(start, len, mayThrow);
    }
    else
    {
+      if (mayThrow)
+         // throw NotYetAvailableException{ mAudioFileName }
+         ;
+
       //fake values.  These values are used usually for normalization and amplifying, so we want
       //the max to be maximal and the min to be minimal
-      *outMin = -1.0;
-      *outMax = 1.0;
-      *outRMS = (float)0.707;//sin with amp of 1 rms
+      return {
+         -1.0f, 1.0f, 0.707f //sin with amp of 1 rms
+      };
    }
 }
 
 /// Gets extreme values for the entire block
-void ODDecodeBlockFile::GetMinMax(float *outMin, float *outMax, float *outRMS) const
+auto ODDecodeBlockFile::GetMinMaxRMS(bool mayThrow) const -> MinMaxRMS
 {
   if(IsSummaryAvailable())
    {
-      SimpleBlockFile::GetMinMax(outMin,outMax,outRMS);
+      return SimpleBlockFile::GetMinMaxRMS(mayThrow);
    }
    else
    {
+      if (mayThrow)
+         // throw NotYetAvailableException{ mAudioFileName }
+         ;
+
       //fake values.  These values are used usually for normalization and amplifying, so we want
       //the max to be maximal and the min to be minimal
-      *outMin = -1.0;
-      *outMax = 1.0;
-      *outRMS = (float)0.707;//sin with amp of 1 rms
+      return {
+         -1.0f, 1.0f, 0.707f //sin with amp of 1 rms
+      };
    }
 }
 
diff --git a/src/blockfile/ODDecodeBlockFile.h b/src/blockfile/ODDecodeBlockFile.h
index 3a743ffd9..0a98df679 100644
--- a/src/blockfile/ODDecodeBlockFile.h
+++ b/src/blockfile/ODDecodeBlockFile.h
@@ -63,10 +63,10 @@ class ODDecodeBlockFile final : public SimpleBlockFile
    //Calls that rely on summary files need to be overidden
    DiskByteCount GetSpaceUsage() const override;
    /// Gets extreme values for the specified region
-   void GetMinMax(size_t start, size_t len,
-                          float *outMin, float *outMax, float *outRMS) const override;
+   MinMaxRMS GetMinMaxRMS(
+      size_t start, size_t len, bool mayThrow) const override;
    /// Gets extreme values for the entire block
-   void GetMinMax(float *outMin, float *outMax, float *outRMS) const override;
+   MinMaxRMS GetMinMaxRMS(bool mayThrow) const override;
    /// Returns the 256 byte summary data block
    bool Read256(float *buffer, size_t start, size_t len) override;
    /// Returns the 64K summary data block
diff --git a/src/blockfile/ODPCMAliasBlockFile.cpp b/src/blockfile/ODPCMAliasBlockFile.cpp
index 678d74f88..4f14be7f6 100644
--- a/src/blockfile/ODPCMAliasBlockFile.cpp
+++ b/src/blockfile/ODPCMAliasBlockFile.cpp
@@ -36,6 +36,8 @@ The summary is eventually computed and written to a file in a background thread.
 #include "../ondemand/ODManager.h"
 #include "../AudioIO.h"
 
+#include "NotYetAvailableException.h"
+
 //#include <errno.h>
 
 extern AudioIO *gAudioIO;
@@ -121,37 +123,49 @@ void ODPCMAliasBlockFile::Unlock()
 
 
 /// Gets extreme values for the specified region
-void ODPCMAliasBlockFile::GetMinMax(size_t start, size_t len,
-                          float *outMin, float *outMax, float *outRMS) const
+auto ODPCMAliasBlockFile::GetMinMaxRMS(
+   size_t start, size_t len, bool mayThrow) const -> MinMaxRMS
 {
    if(IsSummaryAvailable())
    {
-      PCMAliasBlockFile::GetMinMax(start,len,outMin,outMax,outRMS);
+      return PCMAliasBlockFile::GetMinMaxRMS(start, len, mayThrow);
    }
    else
    {
+      if (mayThrow)
+         //throw NotYetAvailableException{ GetAliasedFileName() }
+         ;
+
       //fake values.  These values are used usually for normalization and amplifying, so we want
       //the max to be maximal and the min to be minimal
-      *outMin = -1.0*JUST_BELOW_MAX_AUDIO;
-      *outMax = 1.0*JUST_BELOW_MAX_AUDIO;
-      *outRMS = (float)0.707;//sin with amp of 1 rms
+      return {
+         -JUST_BELOW_MAX_AUDIO,
+         JUST_BELOW_MAX_AUDIO,
+         0.707f //sin with amp of 1 rms
+      };
    }
 }
 
 /// Gets extreme values for the entire block
-void ODPCMAliasBlockFile::GetMinMax(float *outMin, float *outMax, float *outRMS) const
+auto ODPCMAliasBlockFile::GetMinMaxRMS(bool mayThrow) const -> MinMaxRMS
 {
   if(IsSummaryAvailable())
    {
-      PCMAliasBlockFile::GetMinMax(outMin,outMax,outRMS);
+      return PCMAliasBlockFile::GetMinMaxRMS(mayThrow);
    }
    else
    {
+      if (mayThrow)
+         //throw NotYetAvailableException{ GetAliasedFileName() }
+         ;
+
       //fake values.  These values are used usually for normalization and amplifying, so we want
       //the max to be maximal and the min to be minimal
-      *outMin = -1.0*JUST_BELOW_MAX_AUDIO;
-      *outMax = 1.0*JUST_BELOW_MAX_AUDIO;
-      *outRMS = (float)0.707;//sin with amp of 1 rms
+      return {
+         -JUST_BELOW_MAX_AUDIO,
+         JUST_BELOW_MAX_AUDIO,
+         0.707f //sin with amp of 1 rms
+      };
    }
 }
 
diff --git a/src/blockfile/ODPCMAliasBlockFile.h b/src/blockfile/ODPCMAliasBlockFile.h
index 1653b1e65..421eadad3 100644
--- a/src/blockfile/ODPCMAliasBlockFile.h
+++ b/src/blockfile/ODPCMAliasBlockFile.h
@@ -65,10 +65,10 @@ class ODPCMAliasBlockFile final : public PCMAliasBlockFile
    //Calls that rely on summary files need to be overidden
    DiskByteCount GetSpaceUsage() const override;
    /// Gets extreme values for the specified region
-   void GetMinMax(size_t start, size_t len,
-                          float *outMin, float *outMax, float *outRMS) const override;
+   MinMaxRMS GetMinMaxRMS(
+      size_t start, size_t len, bool mayThrow) const override;
    /// Gets extreme values for the entire block
-   void GetMinMax(float *outMin, float *outMax, float *outRMS) const override;
+   MinMaxRMS GetMinMaxRMS(bool mayThrow) const override;
    /// Returns the 256 byte summary data block
    bool Read256(float *buffer, size_t start, size_t len) override;
    /// Returns the 64K summary data block
diff --git a/src/effects/Amplify.cpp b/src/effects/Amplify.cpp
index 82437e11f..995b29c2a 100644
--- a/src/effects/Amplify.cpp
+++ b/src/effects/Amplify.cpp
@@ -164,8 +164,8 @@ bool EffectAmplify::Init()
 
    for (Track *t = iter.First(); t; t = iter.Next())
    {
-      float min, max;
-      ((WaveTrack *)t)->GetMinMax(&min, &max, mT0, mT1);
+      auto pair = ((WaveTrack *)t)->GetMinMax(mT0, mT1); // may throw
+      const float min = pair.first, max = pair.second;
       float newpeak = (fabs(min) > fabs(max) ? fabs(min) : fabs(max));
 
       if (newpeak > mPeak)
diff --git a/src/effects/Contrast.cpp b/src/effects/Contrast.cpp
index c5cc25bfd..55ffd0bb9 100644
--- a/src/effects/Contrast.cpp
+++ b/src/effects/Contrast.cpp
@@ -84,7 +84,8 @@ bool ContrastDialog::GetDB(float &dB)
          return false;
       }
 
-      ((WaveTrack *)t)->GetRMS(&rms, mT0, mT1);
+      // Don't throw in this analysis dialog
+      rms = ((WaveTrack *)t)->GetRMS(mT0, mT1, false);
       meanSq += rms * rms;
       t = (WaveTrack *) iter.Next();
    }
diff --git a/src/effects/Normalize.cpp b/src/effects/Normalize.cpp
index db3626144..838f6d4dd 100644
--- a/src/effects/Normalize.cpp
+++ b/src/effects/Normalize.cpp
@@ -344,7 +344,10 @@ bool EffectNormalize::AnalyseTrack(const WaveTrack * track, const wxString &msg,
          wxMilliSleep(100);
       }
 
-      track->GetMinMax(&min, &max, mCurT0, mCurT1);
+      // set mMin, mMax.  No progress bar here as it's fast.
+      auto pair = track->GetMinMax(mCurT0, mCurT1); // may throw
+      min = pair.first, max = pair.second;
+
    } else {
       min = -1.0, max = 1.0;   // sensible defaults?
    }
diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp
index 6d4736bb8..ff3607504 100644
--- a/src/effects/nyquist/Nyquist.cpp
+++ b/src/effects/nyquist/Nyquist.cpp
@@ -968,7 +968,8 @@ bool NyquistEffect::ProcessOne()
          if (mCurNumChannels > 1) clips += wxT(" )");
 
          float min, max;
-         mCurTrack[i]->GetMinMax(&min, &max, mT0, mT1);
+         auto pair = mCurTrack[i]->GetMinMax(mT0, mT1); // may throw
+         min = pair.first, max = pair.second;
          maxPeak = wxMax(wxMax(fabs(min), fabs(max)), maxPeak);
          maxPeakLevel = wxMax(maxPeakLevel, maxPeak);
 
@@ -980,8 +981,7 @@ bool NyquistEffect::ProcessOne()
             peakString += wxT("nil");
          }
 
-         float rms = 0.0;
-         mCurTrack[i]->GetRMS(&rms, mT0, mT1);
+         float rms = mCurTrack[i]->GetRMS(mT0, mT1); // may throw
          if (!std::isinf(rms) && !std::isnan(rms)) {
             rmsString += wxString::Format(wxT("(float %s) "), Internat::ToString(rms).c_str());
          } else {