42#include <wx/checkbox.h>
44#include <wx/dcclient.h>
45#include <wx/dcmemory.h>
49#include <wx/scrolbar.h>
51#include <wx/statbmp.h>
52#include <wx/stattext.h>
53#include <wx/statusbr.h>
55#include <wx/textctrl.h>
56#include <wx/textfile.h>
58#include <wx/wfstream.h>
59#include <wx/txtstrm.h>
90#if wxUSE_ACCESSIBILITY
94#define FrequencyAnalysisTitle XO("Frequency Analysis")
114#define FREQ_WINDOW_WIDTH 480
115#define FREQ_WINDOW_HEIGHT 330
191 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX),
193, mAnalyst(std::make_unique<SpectrumAnalyst>())
202 gPrefs->
Read(
wxT(
"/FrequencyPlotDialog/DrawGrid"), &mDrawGrid,
true);
203 gPrefs->
Read(
wxT(
"/FrequencyPlotDialog/SizeChoice"), &mSize, 3);
206 gPrefs->
Read(
wxT(
"/FrequencyPlotDialog/AlgChoice"), &alg, 0);
209 gPrefs->
Read(
wxT(
"/FrequencyPlotDialog/FuncChoice"), &mFunc, 3);
210 gPrefs->
Read(
wxT(
"/FrequencyPlotDialog/AxisChoice"), &mAxis, 1);
225 XO(
"Standard Autocorrelation") ,
226 XO(
"Cuberoot Autocorrelation") ,
227 XO(
"Enhanced Autocorrelation") ,
251 funcChoices.push_back(
259 XO(
"Linear frequency") ,
260 XO(
"Log frequency") ,
263 mFreqFont = wxFont(
fontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
264 mArrowCursor = std::make_unique<wxCursor>(wxCURSOR_ARROW);
265 mCrossCursor = std::make_unique<wxCursor>(wxCURSOR_CROSS);
269 sizeChoices[
mSize].MSGID().GET().ToLong(&
size);
282 S.SetSizerProportion(1);
283 S.StartMultiColumn(3, wxEXPAND);
292 S.StartVerticalLay(2);
295 S.GetParent(), wxID_ANY, wxVERTICAL,
305 S.AddSpace(wxDefaultCoord, 1);
307 .Position(wxALIGN_RIGHT | wxALIGN_TOP)
309 S.AddSpace(wxDefaultCoord, 1);
319 S.StartHorizontalLay(wxEXPAND, 0);
321 S.StartVerticalLay();
324 wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL);
325#if wxUSE_ACCESSIBILITY
332 .Position( wxALIGN_LEFT | wxTOP)
337 S.StartVerticalLay();
339 wxStaticBitmap *zi =
safenew wxStaticBitmap(
S.GetParent(), wxID_ANY, wxBitmap(
ZoomIn));
340 S.Position(wxALIGN_CENTER)
346 wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL);
350 .Position(wxALIGN_CENTER_HORIZONTAL)
352#if wxUSE_ACCESSIBILITY
359 wxStaticBitmap *zo =
safenew wxStaticBitmap(
S.GetParent(), wxID_ANY, wxBitmap(
ZoomOut));
360 S.Position(wxALIGN_CENTER)
365 S.AddSpace(5, wxDefaultCoord);
367 S.EndHorizontalLay();
375 S.StartHorizontalLay(wxEXPAND, 0);
378 S.GetParent(), wxID_ANY, wxHORIZONTAL,
390 S.AddSpace(1, wxDefaultCoord);
392 .Position(wxALIGN_LEFT | wxALIGN_TOP)
394 S.AddSpace(1, wxDefaultCoord);
396 S.EndHorizontalLay();
414 S.StartHorizontalLay(wxEXPAND);
416 S.SetSizerProportion(1);
417 S.StartMultiColumn(6);
421 S.AddPrompt(
XXO(
"Cursor:"));
424 .AddTextBox( {},
wxT(
""), 10);
426 S.AddPrompt(
XXO(
"Peak:"));
429 .AddTextBox( {},
wxT(
""), 10);
436 S.EndHorizontalLay();
449 S.SetSizerProportion(0);
450 S.StartMultiColumn(9, wxALIGN_CENTER);
459 .MinSize( { wxDefaultCoord, wxDefaultCoord } )
460 .AddChoice(
XXO(
"&Algorithm:"), algChoices,
mAlg);
465 .MinSize( { wxDefaultCoord, wxDefaultCoord } )
466 .AddChoice(
XXO(
"&Size:"), sizeChoices,
mSize);
481 .MinSize( { wxDefaultCoord, wxDefaultCoord } )
482 .AddChoice(
XXO(
"&Function:"), funcChoices,
mFunc);
488 .MinSize( { wxDefaultCoord, wxDefaultCoord } )
489 .AddChoice(
XXO(
"&Axis:"), axisChoices,
mAxis);
523 mCloseButton =
static_cast<wxButton*
>(FindWindowById( wxID_CANCEL ));
531 SetMinSize(GetSize());
533#if defined(__WXGTK__)
564 bool shown = IsShown();
590 bool warning =
false;
595 auto start = track->TimeToLongSamples(selectedRegion.t0());
597 mRate = track->GetRate();
598 auto end = track->TimeToLongSamples(selectedRegion.t1());
599 auto dataLen =
end - start;
602 auto maxDataLen = size_t(2) << 26;
603 if (dataLen > maxDataLen) {
611 const auto nChannels = track->NChannels();
612 if (track->GetRate() !=
mRate) {
615 XO(
"To plot the spectrum, all selected tracks must have the same sample rate."),
623 float *
const buffers[]{ buffer1.get(), buffer2.get() };
625 if (!track->GetFloats(
626 0, nChannels, buffers, start,
mDataLen,
false,
631 XO(
"Audio could not be analyzed. This may be due to a stretched or pitch-shifted clip.\nTry resetting any stretched clips, or mixing and rendering the tracks before analyzing"),
640 for (
size_t i = 0; i <
mDataLen; i++)
641 mData[i] = buffers[0][i];
646 const auto buffer = buffers[
iChannel];
647 for (
size_t i = 0; i <
mDataLen; i++)
648 mData[i] += buffer[i];
658"Too much audio was selected. Only the first %.1f seconds of audio will be analyzed.")
686 dc.SetBackground(wxBrush(wxColour(254, 254, 254)));
689 dc.SetPen(*wxBLACK_PEN);
690 dc.SetBrush(*wxWHITE_BRUSH);
698 if (!
mData || mDataLen < mWindowSize || mAnalyst->GetProcessedSize() == 0) {
710 wxString msg =
_(
"Not enough data selected.");
711 wxSize sz = memDC.GetTextExtent(msg);
713 (
mPlotRect.GetWidth() - sz.GetWidth()) / 2,
714 (
mPlotRect.GetHeight() - sz.GetHeight()) / 2);
717 memDC.SelectObject(wxNullBitmap);
727 float yTotal = yRange * ((float)
mZoomSlider->GetValue() / 100.0f);
729 int sTotal = yTotal * 100;
730 int sRange = yRange * 100;
732 mPanScroller->SetScrollbar(sPos, sTotal, sRange, sTotal);
734 float yMax =
mYMax - ((float)sPos / 100);
735 float yMin = yMax - yTotal;
752 vRuler->SetMinSize(wxSize(w2,h));
768 int width = r.width - 2;
770 float xMin, xMax, xRatio, xStep;
775 xRatio = xMax / xMin;
778 xStep = pow(2.0f, (log(xRatio) / log(2.0f)) / width);
783 xStep = (xMax - xMin) / width;
790 xStep = (xMax - xMin) / width;
800 memDC.SetPen(wxPen(
theTheme.
Colour( clrHzPlot ), 1, wxPENSTYLE_SOLID));
802 memDC.SetPen(wxPen(
theTheme.
Colour( clrWavelengthPlot), 1, wxPENSTYLE_SOLID));
806 for (
int i = 0; i < width; i++) {
810 y =
mAnalyst->GetProcessedValue(xPos, xPos * xStep);
812 y =
mAnalyst->GetProcessedValue(xPos, xPos + xStep);
814 float ynorm = (y - yMin) / yTotal;
816 int lineheight = (int)(ynorm * (r.height - 1));
818 if (lineheight > r.height - 2)
819 lineheight = r.height - 2;
822 AColor::Line(memDC, r.x + 1 + i, r.y + r.height - 1 - lineheight,
823 r.x + 1 + i, r.y + r.height - 1);
832 memDC.SetPen(*wxBLACK_PEN);
833 memDC.SetBrush(*wxTRANSPARENT_BRUSH);
834 memDC.DrawRectangle(r);
842 memDC.SelectObject( wxNullBitmap );
850 if (event.Moving() && (event.m_x !=
mMouseX || event.m_y !=
mMouseY)) {
893 mSizeChoice->GetStringSelection().ToLong(&windowSize);
912 wxPaintDC dc( (wxWindow *) event.GetEventObject() );
914 dc.DrawBitmap( *
mBitmap, 0, 0,
true );
923 int width = r.width - 2;
925 float xMin, xMax, xRatio, xStep;
930 xRatio = xMax / xMin;
932 xStep = pow(2.0f, (log(xRatio) / log(2.0f)) / width);
934 xStep = (xMax - xMin) / width;
938 xStep = (xMax - xMin) / width;
946 xPos = xMin * pow(xStep,
mMouseX - (r.x + 1));
948 xPos = xMin + xStep * (
mMouseX - (r.x + 1));
951 float bestpeak =
mAnalyst->FindPeak(xPos, &bestValue);
955 px = (int)(log(bestpeak / xMin) / log(xStep));
957 px = (int)((bestpeak - xMin) * width / (xMax - xMin));
959 dc.SetPen(wxPen(wxColour(255, 32, 32), 1, wxPENSTYLE_SOLID));
960 AColor::Line(dc, r.x + 1 + px, r.y, r.x + 1 + px, r.y + r.height);
967 xPos = xMin * pow(xStep,
mMouseX - (r.x + 1));
968 value =
mAnalyst->GetProcessedValue(xPos, xPos * xStep);
970 xPos = xMin + xStep * (
mMouseX - (r.x + 1));
971 value =
mAnalyst->GetProcessedValue(xPos, xPos + xStep);
981 cursor =
XO(
"%d Hz (%s) = %d dB")
982 .Format( (
int)(xPos + 0.5), xp, (
int)(value + 0.5));
984 peak =
XO(
"%d Hz (%s) = %.1f dB")
985 .Format( (
int)(bestpeak + 0.5), pp, bestValue );
986 }
else if (xPos > 0.0 && bestpeak > 0.0) {
991 cursor =
XO(
"%.4f sec (%d Hz) (%s) = %f")
992 .Format( xPos, (
int)(1.0 / xPos + 0.5), xp, value );
995 peak =
XO(
"%.4f sec (%d Hz) (%s) = %.3f")
996 .Format( bestpeak, (
int)(1.0 / bestpeak + 0.5), pp, bestValue );
1008 dc.SetPen(*wxBLACK_PEN);
1009 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1010 dc.DrawRectangle(r);
1032 wxCommandEvent e(EVT_FREQWINDOW_RECALC, wxID_ANY);
1033 GetEventHandler()->AddPendingEvent(e);
1053 std::optional<wxWindowDisabler> blocker;
1055 blocker.emplace(
this);
1063 hadFocus->SetFocus();
1083 wxString fName =
_(
"spectrum.txt");
1085 fName =
SelectFile(FileNames::Operation::Export,
1086 XO(
"Export Spectral Data As:"),
1091 wxFD_SAVE | wxRESIZE_BORDER,
1097 wxFFileOutputStream ffStream{ fName };
1098 if (!ffStream.IsOk()) {
1103 wxTextOutputStream ss(ffStream);
1105 const int processedSize =
mAnalyst->GetProcessedSize();
1106 const float *
const processed =
mAnalyst->GetProcessed();
1109 <<
XO(
"Frequency (Hz)\tLevel (dB)") <<
'\n';
1110 for (
int i = 1; i < processedSize; i++)
1112 << wxString::Format(
wxT(
"%f\t%f\n"),
1117 <<
XO(
"Lag (seconds)\tFrequency (Hz)\tLevel") <<
'\n';
1118 for (
int i = 1; i < processedSize; i++)
1120 << wxString::Format(
wxT(
"%f\t%f\t%f\n"),
1148 bool shown = IsShown();
1155 auto sizeChoice =
mSizeChoice->GetStringSelection();
1170 long windowSize = 0;
1171 sizeChoice.ToLong(&windowSize);
1189BEGIN_EVENT_TABLE(
FreqPlot, wxWindow)
1196: wxWindow(parent, winid)
1246 freqWindow->
Show(
true);
1247 freqWindow->Raise();
1248 freqWindow->SetFocus();
1258 wxT(
"Analyze/Analyzers/Windows")
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Toolkit-neutral facade for basic user interface services.
const ReservedCommandFlag & AudioIONotBusyFlag()
const ReservedCommandFlag & TimeSelectedFlag()
const ReservedCommandFlag & WaveTracksSelectedFlag()
IntSetting DecibelScaleCutoff
Negation of this value is the lowest dB level that should be shown in dB scales.
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString WindowFuncName(int whichFunction)
#define FrequencyAnalysisTitle
static const char * ZoomOut[]
#define FREQ_WINDOW_HEIGHT
DEFINE_EVENT_TYPE(EVT_FREQWINDOW_RECALC)
static const char * ZoomIn[]
XXO("&Cut/Copy/Paste Toolbar")
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
TranslatableString PitchName_Absolute(const double dMIDInote, const PitchNameChoice choice)
double FreqToMIDInote(const double freq)
audacity::BasicSettings * gPrefs
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
AUDACITY_DLL_API AttachedWindows & GetAttachedWindows(AudacityProject &project)
accessors for certain important windows associated with each project
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
void RegisterLastAnalyzer(const CommandContext &context)
static CommandManager & Get(AudacityProject &project)
FILES_API const FileType AllFiles
FILES_API const FileType TextFiles
Works with FrequencyPlotDialog to display a spectrum plot of the waveform. This class actually does t...
void OnErase(wxEraseEvent &event)
bool AcceptsFocus() const
void OnMouseEvent(wxMouseEvent &event)
void OnPaint(wxPaintEvent &event)
FrequencyPlotDialog * freqWindow
Displays a spectrum plot of the waveform. Has options for selecting parameters of the plot.
std::unique_ptr< wxCursor > mArrowCursor
std::unique_ptr< wxBitmap > mBitmap
void OnGetURL(wxCommandEvent &event)
void OnAlgChoice(wxCommandEvent &event)
void OnPanScroller(wxScrollEvent &event)
void OnZoomSlider(wxCommandEvent &event)
void OnAxisChoice(wxCommandEvent &event)
std::unique_ptr< wxCursor > mCrossCursor
void OnRecalc(wxCommandEvent &event)
SpectrumAnalyst::Algorithm mAlg
virtual ~FrequencyPlotDialog()
std::unique_ptr< SpectrumAnalyst > mAnalyst
void OnFuncChoice(wxCommandEvent &event)
void OnCloseButton(wxCommandEvent &event)
void UpdatePrefs() override
static const int fontSize
void OnReplot(wxCommandEvent &event)
void OnCloseWindow(wxCloseEvent &event)
void OnExport(wxCommandEvent &event)
void PlotPaint(wxPaintEvent &event)
void OnSize(wxSizeEvent &event)
void OnGridOnOff(wxCommandEvent &event)
bool Show(bool show=true) override
void OnSizeChoice(wxCommandEvent &event)
void DrawBackground(wxMemoryDC &dc)
wxScrollBar * mPanScroller
void PlotMouseEvent(wxMouseEvent &event)
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
static const LinearUpdater & Instance()
static const LogarithmicUpdater & Instance()
Generates classes whose instances register items at construction.
void DrawGrid(wxDC &dc, int length, bool minor=true, bool major=true, int xOffset=0, int yOffset=0) const
void SetUpdater(const RulerUpdater *pUpdater)
void SetFormat(const RulerFormat *pFormat)
void GetMaxSize(wxCoord *width, wxCoord *height)
void SetUnits(const TranslatableString &units)
void SetRange(double min, double max)
RulerPanel class allows you to work with a Ruler like any other wxWindow.
std::pair< double, double > Range
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined */
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
wxColour & Colour(int iIndex)
static TrackList & Get(AudacityProject &project)
auto Selected() -> TrackIterRange< TrackType >
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
NotifyingSelectedRegion selectedRegion
static ViewInfo & Get(AudacityProject &project)
A Track that contains audio waveform data.
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
virtual bool Flush() noexcept=0
virtual bool Write(const wxString &key, bool value)=0
virtual bool Read(const wxString &key, bool *value) const =0
void SetTitle(const TranslatableString &title)
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
ExportResult Show(ExportTask exportTask)
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
void OnPlotSpectrum(const CommandContext &context)
AttachedWindows::RegisteredFactory sFrequencyWindowKey
MessageBoxOptions && Caption(TranslatableString caption_) &&
Options & LabelEdges(bool l)