Update of /cvsroot/audacity/audacity-src/src
In directory sc8-pr-cvs11.sourceforge.net:/tmp/cvs-serv14652/src

Modified Files:
        Spectrum.cpp Spectrum.h TrackArtist.cpp WaveClip.cpp 
Log Message:
Improvements to Spectrum view by Salvo Ventura (with a little input from me).  
From his comments:
Added support for autoMaxFrequency, so that spectrum plot automatically scales 
up to Fs/2
GetSpectrogram now saves and retrieves autoMaxFrequency and WindowType from 
config. This is configurable from prefs.
DrawVRuler now draws a vertical rules also in the case of Spectrum
Added optional parameter windowFunc to ComputeSpectrum
Consolidated some for loops in a single one (Spectrum.cpp)
Changed the todB_a for a "10*log10" with control (Spectrum.cpp)
Added selection box for windowType and checkBox for AutoMaxFrequency to scale 
the y axis in spectrum view
All params are saved in config file.
Disable the MaxFreq control when AutoMaxFrequency is TRUE (thx to James)

Index: Spectrum.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/Spectrum.cpp,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- Spectrum.cpp        15 Jun 2006 14:26:13 -0000      1.11
+++ Spectrum.cpp        30 Nov 2006 01:03:01 -0000      1.12
@@ -13,7 +13,6 @@
 
 *//*******************************************************************/
 
-
 #include <math.h>
 
 #include "Spectrum.h"
@@ -37,10 +36,8 @@
 bool ComputeSpectrum(float * data, int width, int height,
                      int maxFreq, int windowSize,
                      double rate, float *grayscaleOut,
-                     bool autocorrelation)
+                     bool autocorrelation, int windowFunc)
 {
-   int windowFunc = 3;
-
    if (width < windowSize)
       return false;
 
@@ -83,15 +80,13 @@
          // Take FFT
          FFT(windowSize, false, in, NULL, out, out2);
 
-         // Take real part of result
-         for (i = 0; i < half; i++)
-            processed[i] += out[i];
-      } else {
+      }
+      else
          PowerSpectrum(windowSize, in, out);
 
-         for (i = 0; i < half; i++)
-            processed[i] += out[i];
-      }
+      // Take real part of result
+      for (i = 0; i < half; i++)
+        processed[i] += out[i];
 
       start += half;
       windows++;
@@ -105,32 +100,36 @@
       maxSamples = half;
 
       // Peak Pruning as described by Tolonen and Karjalainen, 2000
-
-      // Clip at zero, copy to temp array
+      /*
+       Combine most of the calculations in a single for loop.
+       It should be safe, as indexes refer only to current and previous 
elements,
+       that have already been clipped, etc...
+      */
       for (i = 0; i < maxSamples; i++) {
-         if (processed[i] < 0.0)
+        // Clip at zero, copy to temp array
+        if (processed[i] < 0.0)
             processed[i] = float(0.0);
-         out[i] = processed[i];
-      }
-
-      // Subtract a time-doubled signal (linearly interp.) from the original
-      // (clipped) signal
-      for (i = 0; i < maxSamples; i++)
-         if ((i % 2) == 0)
-            processed[i] -= out[i / 2];
-         else
-            processed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2);
+        out[i] = processed[i];
+        // Subtract a time-doubled signal (linearly interp.) from the original
+        // (clipped) signal
+        if ((i % 2) == 0)
+           processed[i] -= out[i / 2];
+        else
+           processed[i] -= ((out[i / 2] + out[i / 2 + 1]) / 2);
 
-      // Clip at zero again
-      for (i = 0; i < maxSamples; i++)
-         if (processed[i] < 0.0)
+        // Clip at zero again
+        if (processed[i] < 0.0)
             processed[i] = float(0.0);
 
-      // Find new max
-      float max = 0;
-      for (i = 1; i < maxSamples; i++)
-         if (processed[i] > max)
-            max = processed[i];
+        // Find new max: only for i>0: unused!?!
+        /*
+        if(i) {
+          if (processed[i] > max)
+             max = processed[i];
+        }
+        */
+      }
+
 
       // Reverse and scale
       for (i = 0; i < maxSamples; i++)
@@ -140,10 +139,12 @@
    } else {
       // Convert to decibels
       // But do it safely; -Inf is nobody's friend
-
       for (i = 0; i < maxSamples; i++){
          float temp=(processed[i] / windowSize / windows);
-         processed[i] = todB_a(&temp);
+         if (temp > 0.0)
+            processed[i] = 10*log10(temp);
+         else
+            processed[i] = 0;
       }
    }
 
@@ -172,7 +173,7 @@
       }
 
       if (!autocorrelation) {
-         // Last step converts dB to a 0.0-1.0 range     
+         // Last step converts dB to a 0.0-1.0 range
          value = (value + 80.0) / 80.0;
       }
 

Index: Spectrum.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/Spectrum.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- Spectrum.h  2 Oct 2003 02:34:12 -0000       1.4
+++ Spectrum.h  30 Nov 2006 01:03:01 -0000      1.5
@@ -23,7 +23,7 @@
 
 bool ComputeSpectrum(float * data, int width, int height,
                      int maxFrequency, int windowSize,
-                     double rate, float *out, bool autocorrelation);
+                     double rate, float *out, bool autocorrelation, int 
windowFunc=3);
 
 #endif
 

Index: WaveClip.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/WaveClip.cpp,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- WaveClip.cpp        20 Nov 2006 13:54:38 -0000      1.23
+++ WaveClip.cpp        30 Nov 2006 01:03:01 -0000      1.24
@@ -20,12 +20,11 @@
 *//****************************************************************//**
 
 \class SpecCache
-\brief Cache used with WaveClip to cache spectrum information (for 
+\brief Cache used with WaveClip to cache spectrum information (for
 drawing).
 
 *//*******************************************************************/
 
-
 #include <math.h>
 #include <wx/log.h>
 
@@ -75,6 +74,7 @@
 public:
    SpecCache(int cacheLen, int viewHeight, bool autocorrelation)
    {
+      windowTypeOld = -1;
       maxFreqPrefOld = -1;
       windowSizeOld = -1;
       dirty = -1;
@@ -93,6 +93,7 @@
       delete[] where;
    }
 
+   int          windowTypeOld;
    int          maxFreqPrefOld;
    int          windowSizeOld;
    int          dirty;
@@ -380,10 +381,20 @@
                                double t0, double pixelsPerSecond,
                                bool autocorrelation)
 {
+   int windowType;
+   bool autoMaxFrequency;
+
    int maxFreqPref = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000);
    int windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
-   
+   gPrefs->Read(wxT("/Spectrum/AutoMaxFrequency"), &autoMaxFrequency, false);
+   gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3);
+   if (autoMaxFrequency) {
+      // automatically set frequency to half of sampling rate
+      maxFreqPref=int(mRate/2);
+   }
+
    if (mSpecCache &&
+       mSpecCache->windowTypeOld == windowType &&
        mSpecCache->maxFreqPrefOld == maxFreqPref &&
        mSpecCache->windowSizeOld == windowSize &&
        mSpecCache->dirty == mDirty &&
@@ -419,6 +430,7 @@
    // with the current one, re-use as much of the cache as
    // possible
    if (oldCache->dirty == mDirty &&
+       oldCache->windowTypeOld == windowType &&
        oldCache->maxFreqPrefOld == maxFreqPref &&
        oldCache->windowSizeOld == windowSize &&
        oldCache->pps == pixelsPerSecond &&
@@ -448,6 +460,7 @@
    }
 
    float *buffer = new float[windowSize];
+   mSpecCache->windowTypeOld = windowType;
    mSpecCache->maxFreqPrefOld = maxFreqPref;
    mSpecCache->windowSizeOld = windowSize;
 
@@ -463,18 +476,18 @@
             for (i = 0; i < (sampleCount)height; i++)
                mSpecCache->freq[height * x + i] = 0;
 
-         } else {
-         
+         }
+         else
+         {
             float *adj = buffer;
             start -= windowSize >> 1;
-            
+
             if (start < 0) {
                for (i = start; i < 0; i++)
                   *adj++ = 0;
                len += start;
                start = 0;
             }
-
             if (start + len > mSequence->GetNumSamples()) {
                len = mSequence->GetNumSamples() - start;
                for (i = len; i < (sampleCount)windowSize; i++)
@@ -487,7 +500,7 @@
             ComputeSpectrum(buffer, windowSize, height,
                             maxFreqPref, windowSize,
                             mRate, &mSpecCache->freq[height * x],
-                            autocorrelation);
+                            autocorrelation, windowType);
          }
       }
 
@@ -1060,7 +1073,7 @@
          error = true;
          break;
       }
-      
+
       if (!newSequence->Append((samplePtr)outBuffer, floatSample,
                                outGenerated))
       {

Index: TrackArtist.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/TrackArtist.cpp,v
retrieving revision 1.86
retrieving revision 1.87
diff -u -d -r1.86 -r1.87
--- TrackArtist.cpp     18 Nov 2006 09:01:37 -0000      1.86
+++ TrackArtist.cpp     30 Nov 2006 01:03:01 -0000      1.87
@@ -240,6 +240,7 @@
 {
    if (t->GetKind() == Track::Wave
        && ((WaveTrack *) t)->GetDisplay() == 0) {
+      // Waveform
       wxRect bev = r;
       bev.Inflate(-1, -1);
       AColor::Bevel(*dc, true, bev);
@@ -250,6 +251,7 @@
       vruler->SetOrientation(wxVERTICAL);
       vruler->SetRange(max, min);
       vruler->SetFormat(Ruler::RealFormat);
+      vruler->SetUnits(wxT(""));
       vruler->SetLabelEdges(false);
       vruler->Draw(*dc);
    }
@@ -260,6 +262,7 @@
       wxRect bev = r;
       bev.Inflate(-1, -1);
       AColor::Bevel(*dc, true, bev);
+      vruler->SetUnits(wxT(""));
 
       float dBr = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
       float min, max;
@@ -310,34 +313,37 @@
          return;
 
       double rate = ((WaveTrack *) t)->GetRate();
+      bool autoMaxFrequency;
       int windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
-      int maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000);
-      int maxSamples = int (maxFreq * windowSize / rate + 0.5);
-      if (maxSamples > windowSize / 2)
-         maxSamples = windowSize / 2;
-      maxFreq = int (maxSamples * rate / windowSize + 0.5);
-      int minFreq = int (rate / windowSize);
-
-      wxString num;
-      long textWidth, textHeight;
+      int maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), rate/2.);
+      gPrefs->Read(wxT("/Spectrum/AutoMaxFrequency"), &autoMaxFrequency, 
false);
 
-      num.Printf(wxT("%dK"), int (maxFreq / 1000 + 0.5));
-      dc->GetTextExtent(num, &textWidth, &textHeight);
-      dc->DrawText(num, r.x + r.width - 3 - textWidth, r.y + 2);
-      num = wxT("Hz");
-      dc->GetTextExtent(num, &textWidth, &textHeight);
-      dc->DrawText(num, r.x + r.width - 3 - textWidth,
-                   r.y + textHeight + 2);
+      if (autoMaxFrequency) {
+         // automatically set frequency to half of sampling rate
+         maxFreq=int(rate/2);
+      }
+      int minFreq = 0.;
 
-      num.Printf(wxT("%d"), minFreq);
-      dc->GetTextExtent(num, &textWidth, &textHeight);
-      dc->DrawText(num, r.x + r.width - 3 - textWidth,
-                   r.y + r.height - 2 - 2 * textHeight);
+      /*
+         draw the ruler
+         we will use Hz if maxFreq is < 2000, otherwise we represent kHz,
+         and append to the numbers a "k"
+      */
+      vruler->SetBounds(r.x, r.y+1, r.x + r.width, r.y + r.height-1);
+      vruler->SetOrientation(wxVERTICAL);
+      vruler->SetFormat(Ruler::RealFormat);
+      vruler->SetLabelEdges(true);
+      // use kHz in scale, if appropriate
+      if (maxFreq>=2000) {
+         vruler->SetRange((maxFreq/1000.), (minFreq/1000.));
+         vruler->SetUnits(wxT("k"));
+      } else {
+         // use Hz
+         vruler->SetRange(int(maxFreq), int(minFreq));
+         vruler->SetUnits(wxT(""));
+      }
 
-      num = wxT("Hz");
-      dc->GetTextExtent(num, &textWidth, &textHeight);
-      dc->DrawText(num, r.x + r.width - 3 - textWidth,
-                   r.y + r.height - 2 - textHeight);
+      vruler->Draw(*dc);
    }
 
    if (t->GetKind() == Track::Wave
@@ -651,7 +657,7 @@
          else if (!sel && usingSelPen)
             dc.SetPen(unselectedPen);
          usingSelPen = sel;
-         
+
          if (maxbot[x] != mintop[x]) {
             dc.DrawLine(r.x + x, r.y + maxtop[x],
                         r.x + x, r.y + maxbot[x]);
@@ -735,7 +741,7 @@
          ypos[s] = r.height;
 
    }
-   
+
    // Draw lines
    for (s = 0; s < slen - 1; s++) {
       dc.DrawLine(r.x + xpos[s], r.y + ypos[s],
@@ -1313,7 +1319,7 @@
    sampleCount numSamples = clip->GetNumSamples();
    double tOffset = clip->GetOffset();
    double rate = clip->GetRate();
-   double sps = 1./rate;            
+   double sps = 1./rate;
 
    // if nothing is on the screen
    if ((sampleCount) (h * rate + 0.5) >= numSamples)
@@ -1324,7 +1330,7 @@
 
    double tpre = h - tOffset;
    double tstep = 1.0 / pps;
-   double tpost = tpre + (r.width * tstep); 
+   double tpost = tpre + (r.width * tstep);
    double trackLen = clip->GetEndTime() - clip->GetStartTime();
 
    bool showIndividualSamples = (pps / rate > 0.5);   //zoomed in a lot
@@ -1341,7 +1347,7 @@
    if (t0 > t1)
       t0 = t1;
 
-   sampleCount ssel0 = wxMax(0, int((sel0 - tOffset) * rate + .99)); 
+   sampleCount ssel0 = wxMax(0, int((sel0 - tOffset) * rate + .99));
    sampleCount ssel1 = wxMax(0, int((sel1 - tOffset) * rate + .99));
 
    //trim selection so that it only contains the actual samples
@@ -1466,7 +1472,7 @@
 
 /*
 Note: recall that Allegro attributes end in a type identifying letter.
- 
+
 In addition to standard notes, an Allegro_Note can denote a graphic.
 A graphic is a note with a loud of zero (for quick testing) and an
 attribute named "shapea" set to one of the following atoms:
@@ -1482,7 +1488,7 @@
     polygon
         coordinates are (time, pitch), (x1r, y1r), (x2r, y2r),
           (x3r, y3r), ... are coordinates (since we cannot represent
-          arrays as attribute values, we just generate as many 
+          arrays as attribute values, we just generate as many
           attribute names as we need)
         dur must be the max of xNr-time for all N
     oval
@@ -1501,7 +1507,7 @@
     fonta is one of ['roman', 'swiss', 'modern'] (font, otherwise use default)
     weighta may be 'bold' (font) (default is normal)
     sizei is font size (default is 8)
-    justifys is a string containing two letters, a horizontal code and a 
+    justifys is a string containing two letters, a horizontal code and a
       vertical code. The horizontal code is as follows:
         l: the coordinate is to the left of the string (default)
         c: the coordinate is at the center of the string
@@ -1513,7 +1519,7 @@
         d: the coordinate is at the baseline of the string (default)
       Thus, -justifys:"lt" places the left top of the string at the point
         given by (pitch, time). The default value is "ld".
-    
+
  */
 
 /* Declare Static functions */


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Audacity-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/audacity-cvs

Reply via email to