I have tinkered a bit with the audacity source code:
I wrote a spectrum display with log frequency axis,
and integrated the hidden feature of a log sweep in the tone generator.
I hope someone checks this in...!
Thanks,
Andreas
Here's the patch against the CVS files:
Code: Select all
Index: Printing.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/Printing.cpp,v
retrieving revision 1.2
diff -u -r1.2 Printing.cpp
--- Printing.cpp 15 Jun 2006 14:26:13 -0000 1.2
+++ Printing.cpp 4 Nov 2007 23:45:48 -0000
@@ -108,10 +108,13 @@
&viewInfo, false, false, false, true, false);
break;
case WaveTrack::SpectrumDisplay:
- artist.DrawSpectrum((WaveTrack *)n, *dc, r, &viewInfo, false);
+ artist.DrawSpectrum((WaveTrack *)n, *dc, r, &viewInfo, false, false);
+ break;
+ case WaveTrack::SpectrumLogDisplay:
+ artist.DrawSpectrum((WaveTrack *)n, *dc, r, &viewInfo, false, true);
break;
case WaveTrack::PitchDisplay:
- artist.DrawSpectrum((WaveTrack *)n, *dc, r, &viewInfo, true);
+ artist.DrawSpectrum((WaveTrack *)n, *dc, r, &viewInfo, true, false);
break;
}
break;
Index: TrackArtist.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/TrackArtist.cpp,v
retrieving revision 1.104
diff -u -r1.104 TrackArtist.cpp
--- TrackArtist.cpp 28 Oct 2007 20:45:15 -0000 1.104
+++ TrackArtist.cpp 6 Nov 2007 02:11:58 -0000
@@ -236,10 +236,13 @@
drawEnvelope, drawSamples, drawSliders, true, muted);
break;
case WaveTrack::SpectrumDisplay:
- DrawSpectrum((WaveTrack *)t, dc, rr, viewInfo, false);
+ DrawSpectrum((WaveTrack *)t, dc, rr, viewInfo, false, false);
+ break;
+ case WaveTrack::SpectrumLogDisplay:
+ DrawSpectrum((WaveTrack *)t, dc, rr, viewInfo, false, true);
break;
case WaveTrack::PitchDisplay:
- DrawSpectrum((WaveTrack *)t, dc, rr, viewInfo, true);
+ DrawSpectrum((WaveTrack *)t, dc, rr, viewInfo, true, false);
break;
}
break; // case Wave
@@ -331,22 +334,22 @@
}
if (t->GetKind() == Track::Wave
- && ((WaveTrack *) t)->GetDisplay() == WaveTrack::SpectrumDisplay) {
- // Spectrum
+ && ((WaveTrack *) t)->GetDisplay() == WaveTrack::SpectrumDisplay)
+ { // Spectrum
if (r.height < 60)
return;
+ bool logF = ((WaveTrack *) t)->GetDisplay() == WaveTrack::SpectrumLogDisplay;
double rate = ((WaveTrack *) t)->GetRate();
int freq = lrint(rate/2.);
- int maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), freq);
- if(maxFreq > freq)
- maxFreq = freq;
+ int maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), freq);
+ if(maxFreq > freq)
+ maxFreq = freq;
int minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), 0L);
- if(minFreq < 0) {
- minFreq = 0;
- gPrefs->Write(wxT("/Spectrum/MinFreq"), 0L);
- }
-
+ if(minFreq < 0) {
+ minFreq = 0;
+ gPrefs->Write(wxT("/Spectrum/MinFreq"), 0L);
+ }
/*
draw the ruler
we will use Hz if maxFreq is < 2000, otherwise we represent kHz,
@@ -368,6 +371,35 @@
vruler->Draw(*dc);
}
+ if (t->GetKind() == Track::Wave
+ && ((WaveTrack *) t)->GetDisplay() == WaveTrack::SpectrumLogDisplay)
+ { // SpectrumLog
+ if (r.height < 10)
+ return;
+ double rate = ((WaveTrack *) t)->GetRate();
+ int freq = lrint(rate/2.);
+ int maxFreq = gPrefs->Read(wxT("/SpectrumLog/MaxFreq"), freq);
+ if(maxFreq > freq)
+ maxFreq = freq;
+ int minFreq = gPrefs->Read(wxT("/SpectrumLog/MinFreq"), freq/1000.0);
+ if(minFreq < 1) {
+ minFreq = 1;
+ gPrefs->Write(wxT("/SpectrumLog/MinFreq"), 1L);
+ }
+ /*
+ 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::IntFormat);
+ vruler->SetLabelEdges(true);
+ vruler->SetRange(maxFreq, minFreq);
+ vruler->SetUnits(wxT(""));
+ vruler->SetLog(true);
+ vruler->Draw(*dc);
+ }
if (t->GetKind() == Track::Wave
&& ((WaveTrack *) t)->GetDisplay() == WaveTrack::PitchDisplay) {
@@ -1315,7 +1347,7 @@
void TrackArtist::DrawSpectrum(WaveTrack *track,
wxDC & dc, wxRect & r,
- ViewInfo * viewInfo, bool autocorrelation)
+ ViewInfo * viewInfo, bool autocorrelation, bool logF)
{
// MM: Draw background. We should optimize that a bit more.
dc.SetPen(*wxTRANSPARENT_PEN);
@@ -1336,12 +1368,12 @@
}
for (WaveClipList::Node* it=track->GetClipIterator(); it; it=it->GetNext())
- DrawClipSpectrum(track, it->GetData(), dc, r, viewInfo, autocorrelation);
+ DrawClipSpectrum(track, it->GetData(), dc, r, viewInfo, autocorrelation, logF);
}
void TrackArtist::DrawClipSpectrum(WaveTrack* track, WaveClip *clip,
wxDC & dc, wxRect & r,
- ViewInfo * viewInfo, bool autocorrelation)
+ ViewInfo * viewInfo, bool autocorrelation, bool logF)
{
double h = viewInfo->h;
double pps = viewInfo->zoom;
@@ -1457,14 +1489,27 @@
bool isGrayscale = false;
gPrefs->Read(wxT("/Spectrum/Grayscale"), &isGrayscale, false);
int ifreq = lrint(rate/2);
- int maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), ifreq);
+ int maxFreq;
+ if (!logF)
+ maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), ifreq);
+ else
+ maxFreq = gPrefs->Read(wxT("/SpectrumLog/MaxFreq"), ifreq);
if(maxFreq > ifreq)
maxFreq = ifreq;
- int minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), 0L);
- if(minFreq < 0) {
- minFreq = 0;
- gPrefs->Write(wxT("/Spectrum/MinFreq"), 0L);
- }
+ int minFreq;
+ if (!logF)
+ { minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), 0L);
+ if(minFreq < 0) {
+ minFreq = 0;
+ gPrefs->Write(wxT("/Spectrum/MinFreq"), 0L);
+ }
+ }else
+ { minFreq = gPrefs->Read(wxT("/SpectrumLog/MinFreq"), ifreq/1000.0);
+ if(minFreq < 1) {
+ minFreq = ifreq/1000.0;
+ gPrefs->Write(wxT("/SpectrumLog/MinFreq"), ifreq/1000.0);
+ }
+ }
bool usePxCache = false;
if( !updated && clip->mSpecPxCache->valid && (clip->mSpecPxCache->len == mid.height * mid.width) ) {
@@ -1483,57 +1528,119 @@
int x = 0;
sampleCount w1 = (sampleCount) ((t0*rate + x *rate *tstep) + .5);
- while (x < mid.width) {
+
+ while (x < mid.width) {
sampleCount w0 = w1;
w1 = (sampleCount) ((t0*rate + (x+1) *rate *tstep) + .5);
- for (int yy = 0; yy < mid.height; yy++) {
- bool selflag = (ssel0 <= w0 && w1 < ssel1);
- unsigned char rv, gv, bv;
- float value;
-
- if(!usePxCache) {
- float bin0 = float (yy) * binPerPx + minSamples;
- float bin1 = float (yy + 1) * binPerPx + minSamples;
-
-
- if (int (bin1) == int (bin0))
- value = freq[half * x + int (bin0)];
- else {
- float binwidth= bin1 - bin0;
- value = freq[half * x + int (bin0)] * (1.f - bin0 + (int)bin0);
-
- bin0 = 1 + int (bin0);
- while (bin0 < int (bin1)) {
- value += freq[half * x + int (bin0)];
- bin0 += 1.0;
- }
- value += freq[half * x + int (bin1)] * (bin1 - int (bin1));
-
- value /= binwidth;
- }
-
- if (!autocorrelation) {
- // Last step converts dB to a 0.0-1.0 range
- value = (value + 80.0) / 80.0;
- }
-
- if (value > 1.0)
- value = float(1.0);
- if (value < 0.0)
- value = float(0.0);
- clip->mSpecPxCache->values[x * mid.height + yy] = value;
- }
- else
- value = clip->mSpecPxCache->values[x * mid.height + yy];
-
- GetColorGradient(value, selflag, isGrayscale, &rv, &gv, &bv);
-
- int px = ((mid.height - 1 - yy) * mid.width + x) * 3;
- data[px++] = rv;
- data[px++] = gv;
- data[px] = bv;
- }
+ if (!logF)
+ { for (int yy = 0; yy < mid.height; yy++) {
+ bool selflag = (ssel0 <= w0 && w1 < ssel1);
+ unsigned char rv, gv, bv;
+ float value;
+
+ if(!usePxCache) {
+ float bin0 = float (yy) * binPerPx + minSamples;
+ float bin1 = float (yy + 1) * binPerPx + minSamples;
+
+
+ if (int (bin1) == int (bin0))
+ value = freq[half * x + int (bin0)];
+ else {
+ float binwidth= bin1 - bin0;
+ value = freq[half * x + int (bin0)] * (1.f - bin0 + (int)bin0);
+
+ bin0 = 1 + int (bin0);
+ while (bin0 < int (bin1)) {
+ value += freq[half * x + int (bin0)];
+ bin0 += 1.0;
+ }
+ value += freq[half * x + int (bin1)] * (bin1 - int (bin1));
+
+ value /= binwidth;
+ }
+
+ if (!autocorrelation) {
+ // Last step converts dB to a 0.0-1.0 range
+ value = (value + 80.0) / 80.0;
+ }
+
+ if (value > 1.0)
+ value = float(1.0);
+ if (value < 0.0)
+ value = float(0.0);
+ clip->mSpecPxCache->values[x * mid.height + yy] = value;
+ }
+ else
+ value = clip->mSpecPxCache->values[x * mid.height + yy];
+
+ GetColorGradient(value, selflag, isGrayscale, &rv, &gv, &bv);
+
+ int px = ((mid.height - 1 - yy) * mid.width + x) * 3;
+ data[px++] = rv;
+ data[px++] = gv;
+ data[px] = bv;
+ }
+ }else
+ { int x0=x*half;
+ double e=exp(1.0f), f=rate/2/half,
+ lmin=log(double(minFreq)),
+ lmax=log(double(maxFreq)),
+ scale=lmax-lmin,
+ expo=exp(scale);
+ for (int yy = 0; yy < mid.height; yy++) {
+ bool selflag = (ssel0 <= w0 && w1 < ssel1);
+ unsigned char rv, gv, bv;
+ float value;
+
+ if(true) //!usePxCache)
+ { float h=double(yy)/mid.height,
+ yy2=exp(h*scale+lmin)/f;
+ if (int(yy2)>=half)
+ yy2=half-1;
+ if (yy2<0)
+ yy2=0;
+ float bin0 = float (yy2);// * binPerPx + minSamples;
+ float bin1 = float (yy2 + 1);// * binPerPx + minSamples;
+
+ if (int (bin1) == int (bin0))
+ value = freq[x0 + int (bin0)];
+ else {
+ float binwidth= bin1 - bin0;
+ value = freq[x0 + int (bin0)] * (1.f - bin0 + (int)bin0);
+
+ bin0 = 1 + int (bin0);
+ while (bin0 < int (bin1)) {
+ value += freq[x0 + int (bin0)];
+ bin0 += 1.0;
+ }
+ value += freq[x0 + int (bin1)] * (bin1 - int (bin1));
+
+ value /= binwidth;
+ }
+
+ if (!autocorrelation) {
+ // Last step converts dB to a 0.0-1.0 range
+ value = (value + 80.0) / 80.0;
+ }
+
+ if (value > 1.0)
+ value = float(1.0);
+ if (value < 0.0)
+ value = float(0.0);
+ clip->mSpecPxCache->values[x * mid.height + yy] = value;
+ }
+ else
+ value = clip->mSpecPxCache->values[x * mid.height + yy];
+
+ GetColorGradient(value, selflag, isGrayscale, &rv, &gv, &bv);
+
+ int px = ((mid.height - 1 - yy) * mid.width + x) * 3;
+ data[px++] = rv;
+ data[px++] = gv;
+ data[px] = bv;
+ }
+ }
x++;
}
Index: TrackArtist.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/TrackArtist.h,v
retrieving revision 1.27
diff -u -r1.27 TrackArtist.h
--- TrackArtist.h 18 Jun 2007 16:10:54 -0000 1.27
+++ TrackArtist.h 5 Nov 2007 21:27:14 -0000
@@ -69,7 +69,7 @@
void DrawSpectrum(WaveTrack *track,
wxDC & dc, wxRect & r,
- ViewInfo * viewInfo, bool autocorrelation);
+ ViewInfo * viewInfo, bool autocorrelation, bool logF);
void DrawNoteTrack(NoteTrack *track,
wxDC & dc, wxRect & r, ViewInfo * viewInfo);
@@ -94,7 +94,7 @@
void DrawClipSpectrum(WaveTrack *track, WaveClip *clip,
wxDC & dc, wxRect & r,
- ViewInfo * viewInfo, bool autocorrelation);
+ ViewInfo * viewInfo, bool autocorrelation, bool logF);
void SetBackgroundBrushes(wxBrush unselectedBrush, wxBrush selectedBrush,
wxPen unselectedPen, wxPen selectedPen) {
Index: TrackPanel.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/TrackPanel.cpp,v
retrieving revision 1.376
diff -u -r1.376 TrackPanel.cpp
--- TrackPanel.cpp 3 Nov 2007 15:15:14 -0000 1.376
+++ TrackPanel.cpp 6 Nov 2007 02:00:14 -0000
@@ -302,6 +302,7 @@
OnWaveformID,
OnWaveformDBID,
OnSpectrumID,
+ OnSpectrumLogID,
OnPitchID,
OnSplitStereoID,
@@ -505,6 +506,7 @@
mWaveTrackMenu->Append(OnWaveformID, _("Waveform"));
mWaveTrackMenu->Append(OnWaveformDBID, _("Waveform (dB)"));
mWaveTrackMenu->Append(OnSpectrumID, _("Spectrum"));
+ mWaveTrackMenu->Append(OnSpectrumLogID, _("Spectrum log(f)"));
mWaveTrackMenu->Append(OnPitchID, _("Pitch (EAC)"));
mWaveTrackMenu->AppendSeparator();
mWaveTrackMenu->AppendCheckItem(OnChannelMonoID, _("Mono"));
@@ -1233,7 +1235,8 @@
{
if (event.m_x >= GetVRulerOffset() &&
t->GetKind() == Track::Wave &&
- ((WaveTrack *) t)->GetDisplay() <= WaveTrack::SpectrumDisplay) {
+ (((WaveTrack *) t)->GetDisplay() <= WaveTrack::SpectrumDisplay
+ ||((WaveTrack *) t)->GetDisplay() <= WaveTrack::SpectrumLogDisplay)) {
*ppTip = _("Click to vertically zoom in, Shift-click to zoom out, Drag to create a particular zoom region.");
SetCursor(event.ShiftDown()? *mZoomOutCursor : *mZoomInCursor);
}
@@ -2529,7 +2532,8 @@
// don't do anything if track is not wave or Spectrum
if (mCapturedTrack->GetKind() != Track::Wave
- || ((WaveTrack *) mCapturedTrack)->GetDisplay() > WaveTrack::SpectrumDisplay)
+ && ((WaveTrack *) mCapturedTrack)->GetDisplay() != WaveTrack::SpectrumDisplay
+ && ((WaveTrack *) mCapturedTrack)->GetDisplay() != WaveTrack::SpectrumLogDisplay)
return;
mMouseCapture = IsVZooming;
@@ -2575,11 +2579,12 @@
}
float min, max, c, l, binSize = 0.0;
- bool spectrum;
+ bool spectrum, spectrumLog;
int windowSize, minBins = 0;
double rate = ((WaveTrack *)track)->GetRate();
((WaveTrack *) track)->GetDisplay() == WaveTrack::SpectrumDisplay ? spectrum = true : spectrum = false;
- if(spectrum) {
+ spectrumLog=(((WaveTrack *) track)->GetDisplay() == WaveTrack::SpectrumLogDisplay);
+ if(spectrum) {
min = gPrefs->Read(wxT("/Spectrum/MinFreq"), 0L);
if(min < 0)
min = 0;
@@ -2590,22 +2595,30 @@
binSize = rate / windowSize;
minBins = wxMin(10, windowSize/2); //minimum 10 freq bins, unless there are less
}
- else
- track->GetDisplayBounds(&min, &max);
+ else if(spectrumLog) {
+ min = gPrefs->Read(wxT("/SpectrumLog/MinFreq"), rate/2000.0);
+ if(min < 1)
+ min = 1;
+ max = gPrefs->Read(wxT("/SpectrumLog/MaxFreq"), rate/2.);
+ if(max > rate/2.)
+ max = rate/2.;
+ windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
+ binSize = rate / windowSize;
+ minBins = wxMin(10, windowSize/2); //minimum 10 freq bins, unless there are less
+ }else
+ track->GetDisplayBounds(&min, &max);
if (IsDragZooming()) {
// Drag Zoom
float p1, p2, tmin, tmax;
- tmin=min;
- tmax=max;
-
- p1 = (mZoomStart - ypos) / (float)height;
- p2 = (mZoomEnd - ypos) / (float)height;
- max = (tmax * (1.0-p1) + tmin * p1);
- min = (tmax * (1.0-p2) + tmin * p2);
-
// Enforce maximum vertical zoom
if(spectrum) {
+ tmin=min;
+ tmax=max;
+ p1 = (mZoomStart - ypos) / (float)height;
+ p2 = (mZoomEnd - ypos) / (float)height;
+ max = (tmax * (1.0-p1) + tmin * p1);
+ min = (tmax * (1.0-p2) + tmin * p2);
if(min < 0.)
min = 0.;
if(max < min + minBins * binSize)
@@ -2615,7 +2628,21 @@
min = max - minBins * binSize;
}
}
+ else if(spectrumLog) {
+ double xmin = 1-(mZoomEnd - ypos) / (float)height;
+ double xmax = 1-(mZoomStart - ypos) / (float)height;
+ double lmin=log10(min), lmax=log10(max);
+ double d=lmax-lmin;
+ min=wxMax(1.0, pow(10, xmin*d+lmin));
+ max=wxMin(rate/2.0, pow(10, xmax*d+lmin));
+ }
else {
+ tmin=min;
+ tmax=max;
+ p1 = (mZoomStart - ypos) / (float)height;
+ p2 = (mZoomEnd - ypos) / (float)height;
+ max = (tmax * (1.0-p1) + tmin * p1);
+ min = (tmax * (1.0-p2) + tmin * p2);
if (max - min < 0.2) {
c = (min+max)/2;
min = c-0.1;
@@ -2640,6 +2667,15 @@
max = wxMin( rate/2., c + 2*l);
}
}
+ else if(spectrumLog)
+ { c = 0.5;
+ double xmin = c-1;
+ double xmax = c+1;
+ double lmin=log10(min), lmax=log10(max);
+ double d=lmax-lmin;
+ min=wxMax(1.0, pow(10, xmin*d+lmin));
+ max=wxMin(rate/2.0, pow(10, xmax*d+lmin));
+ }
else {
if (min <= -1.0 && max >= 1.0) {
min = -2.0;
@@ -2665,8 +2701,20 @@
c = (max * (1.0-p1) + min * p1);
min = wxMax( 0.0, c - 0.5*l);
max = wxMin( rate/2., min + l);
- }
- else {
+ }else if(spectrumLog)
+ { c = 0.5*(min+max);
+ // Enforce maximum vertical zoom
+ l = wxMax( 10. * binSize, (c - min)); //is this a sensible min? MJS
+
+ p1 = (mZoomStart - ypos) / (float)height;
+ c = 1.0-p1;
+ double xmin = wxMax(0, c-0.25);
+ double xmax = wxMin(1, c+0.25);
+ double lmin=log10(min), lmax=log10(max);
+ double d=lmax-lmin;
+ min=pow(10, xmin*d+lmin);
+ max=pow(10, xmax*d+lmin);
+ }else {
// Zoom in centered on cursor
if (min < -1.0 || max > 1.0) {
@@ -2702,6 +2750,22 @@
}
t = iter.Next();
}
+ }else if(spectrumLog) {
+ gPrefs->Write(wxT("/SpectrumLog/MaxFreq"), (long)max);
+ gPrefs->Write(wxT("/SpectrumLog/MinFreq"), (long)min);
+ TrackListIterator iter(mTracks);
+ Track *t = iter.First();
+ while (t) {
+ if (t->GetKind() == Track::Wave) {
+ WaveTrack *wt = (WaveTrack *)t;
+ WaveClipList::Node* it;
+ for(it=wt->GetClipIterator(); it; it=it->GetNext()) {
+ WaveClip *clip = it->GetData();
+ clip->mSpecPxCache->valid = false;
+ }
+ }
+ t = iter.Next();
+ }
}
else {
track->SetDisplayBounds(min, max);
@@ -5516,6 +5580,7 @@
theMenu->Enable(OnWaveformDBID,
display != WaveTrack::WaveformDBDisplay);
theMenu->Enable(OnSpectrumID, display != WaveTrack::SpectrumDisplay);
+ theMenu->Enable(OnSpectrumLogID, display != WaveTrack::SpectrumLogDisplay);
theMenu->Enable(OnPitchID, display != WaveTrack::PitchDisplay);
WaveTrack * track = (WaveTrack *)t;
Index: WaveTrack.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/WaveTrack.h,v
retrieving revision 1.48
diff -u -r1.48 WaveTrack.h
--- WaveTrack.h 18 Jun 2007 16:10:54 -0000 1.48
+++ WaveTrack.h 4 Nov 2007 23:45:48 -0000
@@ -310,6 +310,7 @@
WaveformDisplay,
WaveformDBDisplay,
SpectrumDisplay,
+ SpectrumLogDisplay,
PitchDisplay
} WaveTrackDisplay;
Index: effects/ToneGen.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/effects/ToneGen.cpp,v
retrieving revision 1.46
diff -u -r1.46 ToneGen.cpp
--- effects/ToneGen.cpp 10 Oct 2007 00:16:22 -0000 1.46
+++ effects/ToneGen.cpp 4 Nov 2007 22:51:22 -0000
@@ -50,24 +50,30 @@
amplitude[1] = float(0.8);
// EnableForChirps();
length = sDefaultGenerateLen;
+ interpolation=0;
}
wxString EffectToneGen::GetEffectDescription() {
// Note: This is useful only after values have been set.
/// todo update to include *all* chirp parameters??
const wxChar* waveformNames[] = {wxT("sine"), wxT("square"), wxT("sawtooth"), wxT("square, no alias")};
+ const wxChar* interpolationNames[] = {wxT("linear"), wxT("logarithmic")};
return wxString::Format(_("Applied effect: Generate %s wave %s, frequency = %.2f Hz, amplitude = %.2f, %.6lf seconds"),
- waveformNames[waveform], mbChirp ? wxT("chirp") : wxT("tone"), frequency[0], amplitude[0], length);
+ waveformNames[waveform], mbChirp ? wxT("chirp") : wxT("tone"),
+ frequency[0], amplitude[0], length, interpolationNames[interpolation]);
}
bool EffectToneGen::PromptUser()
{
wxArrayString waveforms;
+ wxArrayString interpolations;
ToneGenDialog dlog(mParent, mbChirp ? _("Chirp Generator") : _("Tone Generator"));
waveforms.Add(_("Sine"));
waveforms.Add(_("Square"));
waveforms.Add(_("Sawtooth"));
waveforms.Add(_("Square, no alias"));
+ interpolations.Add(_("Linear"));
+ interpolations.Add(_("Logarithmic"));
dlog.isSelection= false;
if (mT1 > mT0) {
@@ -83,6 +89,8 @@
dlog.amplitude[1] = amplitude[1];
dlog.length = length;
dlog.waveforms = &waveforms;
+ dlog.interpolation = interpolation;
+ dlog.interpolations = &interpolations;
dlog.Init();
dlog.TransferDataToWindow();
dlog.Fit();
@@ -96,6 +104,11 @@
frequency[1] = dlog.frequency[1];
amplitude[0] = dlog.amplitude[0];
amplitude[1] = dlog.amplitude[1];
+ interpolation = dlog.interpolation;
+ if (interpolation==0)
+ mbLogInterpolation = false;
+ if (interpolation==1)
+ mbLogInterpolation = true;
if( !mbChirp )
{
frequency[1] = frequency[0];
@@ -341,6 +354,7 @@
S.TieTextBox(wxT(""), frequency[1], 10);
S.TieTextBox(_("Amplitude (0-1)"),amplitude[0], 10);
S.TieTextBox(wxT(""), amplitude[1], 10);
+ S.TieChoice(_("Interpolation:"), interpolation, interpolations);
}
S.EndMultiColumn();
S.StartMultiColumn(2, wxCENTER);
Index: effects/ToneGen.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/effects/ToneGen.h,v
retrieving revision 1.23
diff -u -r1.23 ToneGen.h
--- effects/ToneGen.h 29 Jul 2007 02:15:36 -0000 1.23
+++ effects/ToneGen.h 4 Nov 2007 22:44:32 -0000
@@ -78,6 +78,7 @@
double length;
float logFrequency[2];
double mCurRate;
+ int interpolation;
// mSample is an external placeholder to remember the last "buffer"
// position so we use it to reinitialize from where we left
@@ -114,6 +115,8 @@
double amplitude[2];
double length;
bool isSelection;
+ int interpolation;
+ wxArrayString *interpolations;
private:
TimeTextCtrl *mToneDurationT;
Index: widgets/Ruler.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/widgets/Ruler.cpp,v
retrieving revision 1.44
diff -u -r1.44 Ruler.cpp
--- widgets/Ruler.cpp 5 Jul 2007 11:55:38 -0000 1.44
+++ widgets/Ruler.cpp 6 Nov 2007 00:08:02 -0000
@@ -144,7 +144,7 @@
void Ruler::SetFormat(RulerFormat format)
{
- // IntFormat, RealFormat, TimeFormat, or LinearDBFormat
+ // IntFormat, RealFormat, RealLogFormat, TimeFormat, or LinearDBFormat
if (mFormat != format) {
mFormat = format;
@@ -500,6 +500,32 @@
mMajor = d * 2.0;
break;
+ case RealLogFormat:
+ d = 0.000001;
+ // mDigits is number of digits after the decimal point.
+ mDigits = 6;
+ for(;;) {
+ if (units < d) {
+ mMinor = d;
+ mMajor = d*5.0;
+ return;
+ }
+ d *= 5.0;
+ if (units < d) {
+ mMinor = d;
+ mMajor = d*2.0;
+ return;
+ }
+ d *= 2.0;
+ mDigits--;
+ // More than 10 digit numbers? Something is badly wrong.
+ // Probably units is coming in with too high a value.
+ wxASSERT( mDigits >= -10 );
+ }
+ mDigits++;
+ mMinor = d;
+ mMajor = d * 2.0;
+ break;
}
}
@@ -535,6 +561,13 @@
s.Printf(wxString::Format(wxT("%%.%df"), mDigits), d);
}
break;
+ case RealLogFormat:
+ if (mMinor >= 1.0)
+ s.Printf(wxT("%d"), (int)floor(d+0.5));
+ else {
+ s.Printf(wxString::Format(wxT("%%.%df"), mDigits), d);
+ }
+ break;
case TimeFormat:
if (major) {
if (d < 0) {
@@ -606,7 +639,8 @@
}
if (mUnits != wxT(""))
- s = (s + wxT(" ") + mUnits);
+ s = (s + mUnits);
+// s = (s + wxT(" ") + mUnits);
return s;
}
@@ -882,8 +916,9 @@
}
else {
// log case
-
- double loLog = log10(mMin);
+ mDigits=2; //TODO: implement dynamic digit computation
+
+ double loLog = log10(mMin);
double hiLog = log10(mMax);
double scale = mLength/(hiLog - loLog);
int loDecade = (int) floor(loLog);
@@ -895,28 +930,38 @@
// Major ticks are the decades
double decade = startDecade;
- for(i=loDecade; i<hiDecade; i++) {
- if(i!=loDecade) {
- val = decade;
- if(val > mMin && val < mMax) {
+ int delta=hiDecade-loDecade, steps=abs(delta);
+ double step = delta>=0 ? 10 : 0.1;
+ double rMin=wxMin(mMin, mMax), rMax=wxMax(mMin, mMax);
+ for(i=0; i<=steps; i++)
+ { // if(i!=0)
+ { val = decade;
+ if(val > rMin && val < rMax) {
pos = (int)(((log10(val) - loLog)*scale)+0.5);
Tick(pos, val, true);
}
}
- decade *= 10.;
+ decade *= step;
}
// Minor ticks are multiples of decades
decade = startDecade;
- for(i=loDecade; i<hiDecade; i++) {
- for(j=2; j<=9; j++) {
+ int start, end, mstep;
+ if (delta > 0)
+ { start=2; end=10; mstep=1;
+ }else
+ { start=9; end=1; mstep=-1;
+ }
+ steps++;
+ for(i=0; i<=steps; i++) {
+ for(j=start; j!=end; j+=mstep) {
val = decade * j;
- if(val >= mMin && val < mMax) {
+ if(val >= rMin && val < rMax) {
pos = (int)(((log10(val) - loLog)*scale)+0.5);
Tick(pos, val, false);
}
}
- decade *= 10.;
+ decade *= step;
}
}
Index: widgets/Ruler.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/widgets/Ruler.h,v
retrieving revision 1.20
diff -u -r1.20 Ruler.h
--- widgets/Ruler.h 5 Jul 2007 11:55:38 -0000 1.20
+++ widgets/Ruler.h 5 Nov 2007 23:39:36 -0000
@@ -27,7 +27,8 @@
enum RulerFormat {
IntFormat,
RealFormat,
- TimeFormat,
+ RealLogFormat,
+ TimeFormat,
LinearDBFormat,
};