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