I’ve started using Audacity quite a bit lately for some personal projects. I am familiar with a few other audio editing programs such as Cubase VST and Pro Tools, although it’s been a while since I’ve used them heavily, and most of that was on previous (or in some cases previous^4) versions. Besides a few minor things tripping me up from switching programs, there is one thing that is bugging the crap out of me in this otherwise fine effort: while generating tones or silences, the default duration setting either switches back to mm:ss or mm:ss:samples instead of staying with the last selection, in this case mm:ss milliseconds. Yeah, don’t ask me why, I just work better in ms, unless I’m doing video. This is pretty annoying when you are flying through a project and accidentally generate a 24 second sine wave instead of a .25 second wave, or other similar occurrences. Is this a bug, feature, or none of the above? Is there some setting in preferences I am missing? Is there any way to fix/change/break this problem/option/feature? If this is old news, please chastise me for not searching (though I did) or reading, but if this is new news, consider it a feature request/suggestion. Thanks and cheers, Me
I’ve moved this to the feature request section because as far as I’m aware Audacity has always done that, so my guess is that it is a “feature” rather than a “bug”.
I’ll also add my vote to your suggestion:
Generate menus to default to last used units (or the same units as the Selection Toolbar)
+1
This is a very simple fix but requires adding a few more entries to the Prefs file. The code already exists as the Selection Toolbar already does this. I have implemented it on my personal version of Audacity and had no problems.
Could you tell us more about how you did that, or perhaps a patch?
I’d like to try it out, but I’m not a programmer and I don’t think I’d be able to work it out myself.
A patch might rapidly become stale and almost certainly never be applied. The developers of Audacity are very reluctant to add these kinds of features at this time, because of feature and preferences creep. If the patch were not applied to the SVN head, anyone who wish to use it would need to modify the patch frequently as the SVN HEAD changed, I will attach a patch to this-- .patch files not allowed – attached file trd.patch.txt needs a name change to trd.patch.
Here’s a description of the current situation and enough information so that anyone who is compiling their own version of Audacity may make this change for themselves (all line numbers are approximate).
As we can see, the Selection Toolbar already recalls its state by saving the information in Audacity’s preferences file:
(a snippet from the preference file with default setting)
NewPrefsInitialized=1
Version=1.3.13-alpha-Jul 19 2010
[...]
SelectionFormat=hh:mm:ss
(a snippet after changing that setting)
NewPrefsInitialized=1
Version=1.3.13-alpha-Jul 19 2010
[...]
SelectionFormat=CDDA frames (75 fps)
Here is how the Selection Toolbar does this
srctoolbarsSelectionBar.cpp line number 101 (read in from preferences):
void SelectionBar::Populate()
{
[...]
TimeTextCtrl *ttc = new TimeTextCtrl(this, wxID_ANY, wxT(""), 0.0, mRate);
wxString formatName;
gPrefs->Read(wxT("/SelectionFormat"), &formatName);
wxString format = ttc->GetBuiltinFormat(formatName);
delete ttc;
srctoolbarsSelectionBar.cpp line number 344 (write to preferences):
void SelectionBar::OnUpdate(wxCommandEvent &evt)
{
[...]
TimeTextCtrl *ttc = new TimeTextCtrl(this, wxID_ANY, wxT(""), 0.0, mRate);
wxString formatName(ttc->GetBuiltinName(index));
gPrefs->Write(wxT("/SelectionFormat"), formatName);
delete ttc;
Now we know how to do it. The next step is to decide where to do it. My solution might be overkill for some but what I did was search the entire Audacity project for “new TimeTextCtrl”. This gives me most if not all of the occasions where this kind of control is used:
Find all "new TimeTextCtrl", Regular expressions, Subfolders, Find Results 1, "Entire Solution", "*.c; *.cpp"
D:audioAudacitySVNsrcSnap.cpp(47): ttc = new TimeTextCtrl(p, wxID_ANY, wxT(""), 0.0, p->GetRate());
D:audioAudacitySVNsrcTimerRecordDialog.cpp(337): m_pTimeTextCtrl_Start = new TimeTextCtrl(this, ID_TIMETEXT_START, strFormat);
D:audioAudacitySVNsrcTimerRecordDialog.cpp(356): m_pTimeTextCtrl_End = new TimeTextCtrl(this, ID_TIMETEXT_END, strFormat);
D:audioAudacitySVNsrcTimerRecordDialog.cpp(367): m_pTimeTextCtrl_Duration = new TimeTextCtrl(this, ID_TIMETEXT_DURATION, strFormat1);
D:audioAudacitySVNsrctoolbarsSelectionBar.cpp(113): TimeTextCtrl *ttc = new TimeTextCtrl(this, wxID_ANY, wxT(""), 0.0, mRate);
D:audioAudacitySVNsrctoolbarsSelectionBar.cpp(244): mLeftTime = new TimeTextCtrl(this, OnLeftTimeID, wxT(""), 0.0, mRate);
D:audioAudacitySVNsrctoolbarsSelectionBar.cpp(250): mRightTime = new TimeTextCtrl(this, OnRightTimeID, format, 0.0, mRate);
D:audioAudacitySVNsrctoolbarsSelectionBar.cpp(262): mAudioTime = new TimeTextCtrl(this, -1, format, 0.0, mRate);
D:audioAudacitySVNsrctoolbarsSelectionBar.cpp(357): TimeTextCtrl *ttc = new TimeTextCtrl(this, wxID_ANY, wxT(""), 0.0, mRate);
D:audioAudacitySVNsrcwidgetsGrid.cpp(47): m_control = new TimeTextCtrl(parent,
D:audioAudacitySVNsrcwidgetsTimeTextCtrl.cpp(417): SetAccessible(new TimeTextCtrlAx(this));
Matching lines: 11 Matching files: 5 Total files searched: 873
Since we are trying to change the Timer Record Dialog, let’s look at that code…
srcTimerRecordDialog.cpp line number 320:
void TimerRecordDialog::PopulateOrExchange(ShuttleGui& S)
{
[...]
wxString strFormat = wxT("099 h 060 m 060 s");
[...]
m_pTimeTextCtrl_Start = new TimeTextCtrl(this, ID_TIMETEXT_START, strFormat);
As we can see the Timer Record Dialog uses a hardcoded format string where the Selection Toolbar reads the string in from preferences (note – if the entry does not exist in preferences an appropriate default is used by the call to GetBuiltinFormat ()). What we want to do is read and write a preference for the Timer Record Dialog TimeTextCtrl just like we do for the Selection Toolbar (this involves adding an Event and an Update function plus doing the actual code changes).
srcTimerRecordDialog.h line number 47 add function declaration:
void OnUpdate(wxCommandEvent &evt);
srcTimerRecordDialog.cpp at end-of-file add function definition:
void TimerRecordDialog::OnUpdate(wxCommandEvent &evt)
{
int index = evt.GetInt();
evt.Skip(true);
/* we don't actually need a TimeTextCtrl, but need it's
* translations which are done at runtime */
TimeTextCtrl *ttc = new TimeTextCtrl(this, wxID_ANY, wxT(""), 0.0, 0.0);
wxString formatName(ttc->GetBuiltinName(index));
gPrefs->Write(wxT("/TimerRecordDialogFormat"), formatName);
delete ttc;
}
srcTimerRecordDialog.cpp at line number 67 add the event to the table:
EVT_COMMAND(wxID_ANY, EVT_TIMETEXTCTRL_UPDATED, TimerRecordDialog::OnUpdate)
srcTimerRecordDialog.cpp at line number 320 this is where the real changes are made:
void TimerRecordDialog::PopulateOrExchange(ShuttleGui& S)
{
S.SetBorder(5);
S.StartVerticalLay(true);
{
/* we don't actually need a control yet, but we want to use it's methods
* to do some look-ups, so we'll have to create one. We can't make the
* look-ups static because they depend on translations which are done at
* runtime */
TimeTextCtrl *ttc = new TimeTextCtrl(this, wxID_ANY, wxT(""), 0.0, 0.0);
wxString formatName;
gPrefs->Read(wxT("/TimerRecordDialogFormat"), &formatName);
wxString format = ttc->GetBuiltinFormat(formatName);
delete ttc;
S.StartStatic(_("Start Date and Time"), true);
{
m_pDatePickerCtrl_Start =
new wxDatePickerCtrl(this, // wxWindow *parent,
ID_DATEPICKER_START, // wxWindowID id,
m_DateTime_Start); // const wxDateTime& dt = wxDefaultDateTime,
// const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDP_DEFAULT | wxDP_SHOWCENTURY, const wxValidator& validator = wxDefaultValidator, const wxString& name = "datectrl")
m_pDatePickerCtrl_Start->SetName(_("Start Date"));
m_pDatePickerCtrl_Start->SetRange(wxDateTime::Today(), wxInvalidDateTime); // No backdating.
S.AddWindow(m_pDatePickerCtrl_Start);
m_pTimeTextCtrl_Start = new TimeTextCtrl(this, ID_TIMETEXT_START, format);
m_pTimeTextCtrl_Start->EnableMenu(true);
m_pTimeTextCtrl_Start->SetName(_("Start Time"));
m_pTimeTextCtrl_Start->SetTimeValue(wxDateTime_to_AudacityTime(m_DateTime_Start));
S.AddWindow(m_pTimeTextCtrl_Start);
}
S.EndStatic();
S.StartStatic(_("End Date and Time"), true);
{
m_pDatePickerCtrl_End =
new wxDatePickerCtrl(this, // wxWindow *parent,
ID_DATEPICKER_END, // wxWindowID id,
m_DateTime_End); // const wxDateTime& dt = wxDefaultDateTime,
// const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDP_DEFAULT | wxDP_SHOWCENTURY, const wxValidator& validator = wxDefaultValidator, const wxString& name = "datectrl")
m_pDatePickerCtrl_End->SetRange(m_DateTime_Start, wxInvalidDateTime); // No backdating.
m_pDatePickerCtrl_End->SetName(_("End Date"));
S.AddWindow(m_pDatePickerCtrl_End);
m_pTimeTextCtrl_End = new TimeTextCtrl(this, ID_TIMETEXT_END, format);
m_pTimeTextCtrl_Start->EnableMenu(true);
m_pTimeTextCtrl_End->SetName(_("End Time"));
m_pTimeTextCtrl_End->SetTimeValue(wxDateTime_to_AudacityTime(m_DateTime_End));
S.AddWindow(m_pTimeTextCtrl_End);
}
S.EndStatic();
S.StartStatic(_("Duration"), true);
{
m_pTimeTextCtrl_Duration = new TimeTextCtrl(this, ID_TIMETEXT_DURATION, format);
m_pTimeTextCtrl_Duration->SetName(_("Duration"));
m_pTimeTextCtrl_Duration->SetTimeValue(
Internat::CompatibleToDouble(m_TimeSpan_Duration.GetSeconds().ToString()));
S.AddWindow(m_pTimeTextCtrl_Duration);
}
S.EndStatic();
}
S.EndVerticalLay();
S.AddStandardButtons();
Layout();
Fit();
SetMinSize(GetSize());
Center();
}
This has some GUI defects. The window is hardcoded to a fixed width so the longer styles of time control will not fit–again easy to fix (and does not affect me) but the developers are resistant to that kind of change for some reason. Also, when one changes a single control the other controls do not change until the program is closed and re-opened–one may change them all manually so no big deal.
Error checking is also left out–it may well be fatal to set the “start time” in NTSC Frames, Samples or other non-time based “times”!
NewPrefsInitialized=1
Version=1.3.13-alpha-Jul 21 2010
PrefsVersion=1.1.1r1
[...]
SelectionFormat=CDDA frames (75 fps)
[...]
TimerRecordDialogFormat=samples
trd.patch.txt (4.01 KB)
Thanks very much Edgar. There’s plenty there for me (not a programmer) to chew on. Hopefully have time to try it out at the weekend.
Of course, the simple fix (on a personal basis) is to make the hardcoded format string hardcoded to the format you prefer!
There is a really bad workaround for this. I noticed that my former duration numbers stick if I select hh:mm:ss from the default of 30 seconds-only.
I’m doing a task that requires 5 minutes of tone, repeatedly. Each time I switch from seconds-only to hh:mm:ss, my five minute duration comes back without me typing it in again.
Koz
I’ve moved the gist of this thread to the Pending Feature Requests page in the Audacity Wiki.
I have retained it on the forum here and moved it to Audio Processing so that other readers may benefit from Ed’s code if they want to try the DIY approach.
WC