mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-16 08:34:10 +02:00
Merge branch 'master' into HEAD
This commit is contained in:
commit
b62bddfaeb
@ -2163,14 +2163,17 @@ void LabelTrack::Import(wxTextFile & in)
|
|||||||
//Currently, we expect a tag file to have two values and a label
|
//Currently, we expect a tag file to have two values and a label
|
||||||
//on each line. If the second token is not a number, we treat
|
//on each line. If the second token is not a number, we treat
|
||||||
//it as a single-value label.
|
//it as a single-value label.
|
||||||
|
bool error = false;
|
||||||
for (int index = 0; index < lines;) {
|
for (int index = 0; index < lines;) {
|
||||||
try {
|
try {
|
||||||
// Let LabelStruct::Import advance index
|
// Let LabelStruct::Import advance index
|
||||||
LabelStruct l { LabelStruct::Import(in, index) };
|
LabelStruct l { LabelStruct::Import(in, index) };
|
||||||
mLabels.push_back(l);
|
mLabels.push_back(l);
|
||||||
}
|
}
|
||||||
catch(const LabelStruct::BadFormatException&) {}
|
catch(const LabelStruct::BadFormatException&) { error = true; }
|
||||||
}
|
}
|
||||||
|
if (error)
|
||||||
|
::wxMessageBox( _("One or more saved labels could not be read.") );
|
||||||
SortLabels();
|
SortLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
458
src/Menus.cpp
458
src/Menus.cpp
@ -35,6 +35,7 @@ simplifies construction of menu items.
|
|||||||
|
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
@ -494,11 +495,6 @@ void AudacityProject::CreateMenusAndCommands()
|
|||||||
c->AddItem(wxT("Disjoin"), _("Detac&h at Silences"), FN(OnDisjoin), wxT("Ctrl+Alt+J"));
|
c->AddItem(wxT("Disjoin"), _("Detac&h at Silences"), FN(OnDisjoin), wxT("Ctrl+Alt+J"));
|
||||||
c->EndSubMenu();
|
c->EndSubMenu();
|
||||||
|
|
||||||
c->AddSeparator();
|
|
||||||
|
|
||||||
c->AddItem(wxT("EditMetaData"), _("Me&tadata..."), FN(OnEditMetadata));
|
|
||||||
c->AddSeparator();
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
c->BeginSubMenu(_("La&bels"));
|
c->BeginSubMenu(_("La&bels"));
|
||||||
@ -562,70 +558,7 @@ void AudacityProject::CreateMenusAndCommands()
|
|||||||
|
|
||||||
c->EndSubMenu();
|
c->EndSubMenu();
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
c->AddItem(wxT("EditMetaData"), _("Me&tadata..."), FN(OnEditMetadata));
|
||||||
|
|
||||||
/* i18n-hint: (verb) It's an item on a menu. */
|
|
||||||
c->BeginSubMenu(_("&Select"));
|
|
||||||
c->SetDefaultFlags(TracksExistFlag, TracksExistFlag);
|
|
||||||
|
|
||||||
c->AddItem(wxT("SelectAll"), _("&All"), FN(OnSelectAll), wxT("Ctrl+A"));
|
|
||||||
c->AddItem(wxT("SelectNone"), _("&None"), FN(OnSelectNone), wxT("Ctrl+Shift+A"));
|
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
|
||||||
c->BeginSubMenu(_("S&pectral"));
|
|
||||||
c->AddItem(wxT("ToggleSpectralSelection"), _("To&ggle spectral selection"), FN(OnToggleSpectralSelection), wxT("Q"));
|
|
||||||
c->AddItem(wxT("NextHigherPeakFrequency"), _("Next Higher Peak Frequency"), FN(OnNextHigherPeakFrequency));
|
|
||||||
c->AddItem(wxT("NextLowerPeakFrequency"), _("Next Lower Peak Frequency"), FN(OnNextLowerPeakFrequency));
|
|
||||||
c->EndSubMenu();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
c->AddItem(wxT("SetLeftSelection"), _("&Left at Playback Position"), FN(OnSetLeftSelection), wxT("["));
|
|
||||||
c->AddItem(wxT("SetRightSelection"), _("&Right at Playback Position"), FN(OnSetRightSelection), wxT("]"));
|
|
||||||
|
|
||||||
c->SetDefaultFlags(TracksSelectedFlag, TracksSelectedFlag);
|
|
||||||
|
|
||||||
c->AddItem(wxT("SelStartCursor"), _("Track &Start to Cursor"), FN(OnSelectStartCursor), wxT("Shift+J"));
|
|
||||||
c->AddItem(wxT("SelCursorEnd"), _("Cursor to Track &End"), FN(OnSelectCursorEnd), wxT("Shift+K"));
|
|
||||||
c->AddItem(wxT("SelCursorStoredCursor"), _("Cursor to Saved &Cursor Position"), FN(OnSelectCursorStoredCursor),
|
|
||||||
wxT(""), TracksExistFlag, TracksExistFlag);
|
|
||||||
|
|
||||||
|
|
||||||
c->AddSeparator();
|
|
||||||
|
|
||||||
c->AddItem(wxT("SelAllTracks"), _("In All &Tracks"), FN(OnSelectAllTracks),
|
|
||||||
wxT("Ctrl+Shift+K"),
|
|
||||||
TracksExistFlag, TracksExistFlag);
|
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_SYNC_LOCK
|
|
||||||
c->AddItem(wxT("SelSyncLockTracks"), _("In All Sync-Locked Tracks"),
|
|
||||||
FN(OnSelectSyncLockSel), wxT("Ctrl+Shift+Y"),
|
|
||||||
TracksSelectedFlag | IsSyncLockedFlag,
|
|
||||||
TracksSelectedFlag | IsSyncLockedFlag);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
c->AddSeparator();
|
|
||||||
c->AddItem(wxT("ZeroCross"), _("Ends to &Zero Crossings"), FN(OnZeroCrossing), wxT("Z"));
|
|
||||||
c->AddSeparator();
|
|
||||||
|
|
||||||
c->AddItem(wxT("StoreCursorPosition"), _("Save Cursor Pos&ition"), FN(OnCursorPositionStore),
|
|
||||||
WaveTracksExistFlag,
|
|
||||||
WaveTracksExistFlag);
|
|
||||||
// Save cursor position is used in some selctions.
|
|
||||||
// Maybe there should be a restore for it?
|
|
||||||
|
|
||||||
// Audacity has 'Store Re&gion' here.
|
|
||||||
c->AddItem(wxT("SelSave"), _("Save Sele&ction"), FN(OnSelectionSave),
|
|
||||||
WaveTracksSelectedFlag,
|
|
||||||
WaveTracksSelectedFlag);
|
|
||||||
// Audacity has 'Retrieve Regio&n' here.
|
|
||||||
c->AddItem(wxT("SelRestore"), _("Restore Selectio&n"), FN(OnSelectionRestore),
|
|
||||||
TracksExistFlag,
|
|
||||||
TracksExistFlag);
|
|
||||||
c->EndSubMenu();
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -645,6 +578,104 @@ void AudacityProject::CreateMenusAndCommands()
|
|||||||
AudioIONotBusyFlag,
|
AudioIONotBusyFlag,
|
||||||
AudioIONotBusyFlag);
|
AudioIONotBusyFlag);
|
||||||
|
|
||||||
|
c->EndMenu();
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Select Menu
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/* i18n-hint: (verb) It's an item on a menu. */
|
||||||
|
c->BeginMenu(_("&Select"));
|
||||||
|
c->SetDefaultFlags(TracksExistFlag, TracksExistFlag);
|
||||||
|
|
||||||
|
c->AddItem(wxT("SelectAll"), _("&All"), FN(OnSelectAll), wxT("Ctrl+A"));
|
||||||
|
c->AddItem(wxT("SelectNone"), _("&None"), FN(OnSelectNone), wxT("Ctrl+Shift+A"));
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
c->SetDefaultFlags(TracksSelectedFlag, TracksSelectedFlag);
|
||||||
|
|
||||||
|
c->BeginSubMenu(_("Tracks"));
|
||||||
|
c->AddItem(wxT("SelAllTracks"), _("In All &Tracks"), FN(OnSelectAllTracks),
|
||||||
|
wxT("Ctrl+Shift+K"),
|
||||||
|
TracksExistFlag, TracksExistFlag);
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SYNC_LOCK
|
||||||
|
c->AddItem(wxT("SelSyncLockTracks"), _("In All Sync-Locked Tracks"),
|
||||||
|
FN(OnSelectSyncLockSel), wxT("Ctrl+Shift+Y"),
|
||||||
|
TracksSelectedFlag | IsSyncLockedFlag,
|
||||||
|
TracksSelectedFlag | IsSyncLockedFlag);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
c->EndSubMenu();
|
||||||
|
|
||||||
|
c->SetDefaultFlags(TracksExistFlag, TracksExistFlag);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
c->BeginSubMenu(_("Region"));
|
||||||
|
|
||||||
|
c->AddItem(wxT("SetLeftSelection"), _("&Left at Playback Position"), FN(OnSetLeftSelection), wxT("["));
|
||||||
|
c->AddItem(wxT("SetRightSelection"), _("&Right at Playback Position"), FN(OnSetRightSelection), wxT("]"));
|
||||||
|
c->SetDefaultFlags(TracksSelectedFlag, TracksSelectedFlag);
|
||||||
|
c->AddItem(wxT("SelStartCursor"), _("Track &Start to Cursor"), FN(OnSelectStartCursor), wxT("Shift+J"));
|
||||||
|
c->AddItem(wxT("SelCursorEnd"), _("Cursor to Track &End"), FN(OnSelectCursorEnd), wxT("Shift+K"));
|
||||||
|
c->AddSeparator();
|
||||||
|
// Audacity has 'Store Re&gion' here.
|
||||||
|
c->AddItem(wxT("SelSave"), _("Save Sele&ction"), FN(OnSelectionSave),
|
||||||
|
WaveTracksSelectedFlag,
|
||||||
|
WaveTracksSelectedFlag);
|
||||||
|
// Audacity has 'Retrieve Regio&n' here.
|
||||||
|
c->AddItem(wxT("SelRestore"), _("Restore Selectio&n"), FN(OnSelectionRestore),
|
||||||
|
TracksExistFlag,
|
||||||
|
TracksExistFlag);
|
||||||
|
c->AddSeparator();
|
||||||
|
c->AddItem(wxT("ZeroCross"), _("Ends to &Zero Crossings"), FN(OnZeroCrossing), wxT("Z"));
|
||||||
|
|
||||||
|
c->EndSubMenu();
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
c->SetDefaultFlags(TracksExistFlag, TracksExistFlag);
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
c->BeginSubMenu(_("S&pectral"));
|
||||||
|
c->AddItem(wxT("ToggleSpectralSelection"), _("To&ggle spectral selection"), FN(OnToggleSpectralSelection), wxT("Q"));
|
||||||
|
c->AddItem(wxT("NextHigherPeakFrequency"), _("Next Higher Peak Frequency"), FN(OnNextHigherPeakFrequency));
|
||||||
|
c->AddItem(wxT("NextLowerPeakFrequency"), _("Next Lower Peak Frequency"), FN(OnNextLowerPeakFrequency));
|
||||||
|
c->EndSubMenu();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
c->SetDefaultFlags(TracksSelectedFlag, TracksSelectedFlag);
|
||||||
|
|
||||||
|
c->BeginSubMenu(_("Clip Boundaries"));
|
||||||
|
c->AddItem(wxT("SelPrevClipBoundaryToCursor"), _("Pre&vious Clip Boundary to Cursor"),
|
||||||
|
FN(OnSelectPrevClipBoundaryToCursor), wxT(""),
|
||||||
|
TrackPanelHasFocus | WaveTracksExistFlag, TrackPanelHasFocus | WaveTracksExistFlag);
|
||||||
|
c->AddItem(wxT("SelCursorToNextClipBoundary"), _("Cursor to Ne&xt Clip Boundary"),
|
||||||
|
FN(OnSelectCursorToNextClipBoundary), wxT(""),
|
||||||
|
TrackPanelHasFocus |WaveTracksExistFlag, TrackPanelHasFocus | WaveTracksExistFlag);
|
||||||
|
c->AddItem(wxT("SelPrevClip"), _("Previo&us Clip"), FN(OnSelectPrevClip), wxT(""),
|
||||||
|
WaveTracksExistFlag | TrackPanelHasFocus, WaveTracksExistFlag | TrackPanelHasFocus);
|
||||||
|
c->AddItem(wxT("SelNextClip"), _("N&ext Clip"), FN(OnSelectNextClip), wxT(""),
|
||||||
|
WaveTracksExistFlag | TrackPanelHasFocus, WaveTracksExistFlag | TrackPanelHasFocus);
|
||||||
|
|
||||||
|
c->EndSubMenu();
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
c->AddItem(wxT("SelCursorStoredCursor"), _("Cursor to Saved &Cursor Position"), FN(OnSelectCursorStoredCursor),
|
||||||
|
wxT(""), TracksExistFlag, TracksExistFlag);
|
||||||
|
|
||||||
|
c->AddItem(wxT("StoreCursorPosition"), _("Save Cursor Pos&ition"), FN(OnCursorPositionStore),
|
||||||
|
WaveTracksExistFlag,
|
||||||
|
WaveTracksExistFlag);
|
||||||
|
// Save cursor position is used in some selctions.
|
||||||
|
// Maybe there should be a restore for it?
|
||||||
|
|
||||||
|
|
||||||
c->EndMenu();
|
c->EndMenu();
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
@ -817,6 +848,11 @@ void AudacityProject::CreateMenusAndCommands()
|
|||||||
c->AddItem(wxT("CursTrackStart"), _("Track &Start"), FN(OnCursorTrackStart), wxT("J"));
|
c->AddItem(wxT("CursTrackStart"), _("Track &Start"), FN(OnCursorTrackStart), wxT("J"));
|
||||||
c->AddItem(wxT("CursTrackEnd"), _("Track &End"), FN(OnCursorTrackEnd), wxT("K"));
|
c->AddItem(wxT("CursTrackEnd"), _("Track &End"), FN(OnCursorTrackEnd), wxT("K"));
|
||||||
|
|
||||||
|
c->AddItem(wxT("CursPrevClipBoundary"), _("Pre&vious Clip Boundary"), FN(OnCursorPrevClipBoundary), wxT(""),
|
||||||
|
TrackPanelHasFocus | WaveTracksExistFlag, TrackPanelHasFocus | WaveTracksExistFlag);
|
||||||
|
c->AddItem(wxT("CursNextClipBoundary"), _("Ne&xt Clip Boundary"), FN(OnCursorNextClipBoundary), wxT(""),
|
||||||
|
TrackPanelHasFocus | WaveTracksExistFlag, TrackPanelHasFocus | WaveTracksExistFlag);
|
||||||
|
|
||||||
c->AddItem(wxT("CursProjectStart"), _("&Project Start"), FN(OnSkipStart), wxT("Home"));
|
c->AddItem(wxT("CursProjectStart"), _("&Project Start"), FN(OnSkipStart), wxT("Home"));
|
||||||
c->AddItem(wxT("CursProjectEnd"), _("Project E&nd"), FN(OnSkipEnd), wxT("End"));
|
c->AddItem(wxT("CursProjectEnd"), _("Project E&nd"), FN(OnSkipEnd), wxT("End"));
|
||||||
|
|
||||||
@ -918,6 +954,13 @@ void AudacityProject::CreateMenusAndCommands()
|
|||||||
c->AddItem(wxT("UnMuteAllTracks"), _("&Unmute All Tracks"), FN(OnUnMuteAllTracks), wxT("Ctrl+Shift+U"));
|
c->AddItem(wxT("UnMuteAllTracks"), _("&Unmute All Tracks"), FN(OnUnMuteAllTracks), wxT("Ctrl+Shift+U"));
|
||||||
c->EndSubMenu();
|
c->EndSubMenu();
|
||||||
|
|
||||||
|
c->BeginSubMenu("Pan");
|
||||||
|
c->AddItem(wxT("PanLeft"), _("&Left"), FN(OnPanLeft));
|
||||||
|
c->AddItem(wxT("PanRight"), _("&Right"), FN(OnPanRight));
|
||||||
|
c->AddItem(wxT("PanCenter"), _("&Center"), FN(OnPanCenter));
|
||||||
|
c->EndSubMenu();
|
||||||
|
|
||||||
|
|
||||||
c->AddSeparator();
|
c->AddSeparator();
|
||||||
|
|
||||||
wxArrayString alignLabelsNoSync;
|
wxArrayString alignLabelsNoSync;
|
||||||
@ -1260,6 +1303,9 @@ void AudacityProject::CreateMenusAndCommands()
|
|||||||
c->AddCommand(wxT("CursorLongJumpLeft"), _("Cursor Long Jump Left"), FN(OnCursorLongJumpLeft), wxT("Shift+,"));
|
c->AddCommand(wxT("CursorLongJumpLeft"), _("Cursor Long Jump Left"), FN(OnCursorLongJumpLeft), wxT("Shift+,"));
|
||||||
c->AddCommand(wxT("CursorLongJumpRight"), _("Cursor Long Jump Right"), FN(OnCursorLongJumpRight), wxT("Shift+."));
|
c->AddCommand(wxT("CursorLongJumpRight"), _("Cursor Long Jump Right"), FN(OnCursorLongJumpRight), wxT("Shift+."));
|
||||||
|
|
||||||
|
c->AddCommand(wxT("ClipLeft"), _("Clip Left"), FN(OnClipLeft), wxT(""));
|
||||||
|
c->AddCommand(wxT("ClipRight"), _("Clip Right"), FN(OnClipRight), wxT(""));
|
||||||
|
|
||||||
c->AddCommand(wxT("SelExtLeft"), _("Selection Extend Left"), FN(OnSelExtendLeft), wxT("Shift+Left\twantKeyup\tallowDup"));
|
c->AddCommand(wxT("SelExtLeft"), _("Selection Extend Left"), FN(OnSelExtendLeft), wxT("Shift+Left\twantKeyup\tallowDup"));
|
||||||
c->AddCommand(wxT("SelExtRight"), _("Selection Extend Right"), FN(OnSelExtendRight), wxT("Shift+Right\twantKeyup\tallowDup"));
|
c->AddCommand(wxT("SelExtRight"), _("Selection Extend Right"), FN(OnSelExtendRight), wxT("Shift+Right\twantKeyup\tallowDup"));
|
||||||
|
|
||||||
@ -2914,6 +2960,16 @@ void AudacityProject::OnSelContractRight(const wxEvent * evt)
|
|||||||
OnCursorLeft( true, true, evt->GetEventType() == wxEVT_KEY_UP );
|
OnCursorLeft( true, true, evt->GetEventType() == wxEVT_KEY_UP );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnClipLeft()
|
||||||
|
{
|
||||||
|
mTrackPanel->OnClipMove(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnClipRight()
|
||||||
|
{
|
||||||
|
mTrackPanel->OnClipMove(true);
|
||||||
|
}
|
||||||
|
|
||||||
//this pops up a dialog which allows the left selection to be set.
|
//this pops up a dialog which allows the left selection to be set.
|
||||||
//If playing/recording is happening, it sets the left selection at
|
//If playing/recording is happening, it sets the left selection at
|
||||||
//the current play position.
|
//the current play position.
|
||||||
@ -5309,6 +5365,110 @@ void AudacityProject::OnSelectStartCursor()
|
|||||||
mTrackPanel->Refresh(false);
|
mTrackPanel->Refresh(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnSelectPrevClipBoundaryToCursor()
|
||||||
|
{
|
||||||
|
OnSelectClipBoundary(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnSelectCursorToNextClipBoundary()
|
||||||
|
{
|
||||||
|
OnSelectClipBoundary(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnSelectClipBoundary(bool next)
|
||||||
|
{
|
||||||
|
const auto track = mTrackPanel->GetFocusedTrack();
|
||||||
|
|
||||||
|
if (track && track->GetKind() == Track::Wave) {
|
||||||
|
const auto wt = static_cast<WaveTrack*>(track);
|
||||||
|
if (wt->GetNumClips()) {
|
||||||
|
auto result = next ? FindNextClipBoundary(wt, mViewInfo.selectedRegion.t1()) :
|
||||||
|
FindPrevClipBoundary(wt, mViewInfo.selectedRegion.t0());
|
||||||
|
|
||||||
|
if (result.nFound > 0) {
|
||||||
|
if (next)
|
||||||
|
mViewInfo.selectedRegion.setT1(result.time);
|
||||||
|
else
|
||||||
|
mViewInfo.selectedRegion.setT0(result.time);
|
||||||
|
|
||||||
|
ModifyState(false);
|
||||||
|
mTrackPanel->Refresh(false);
|
||||||
|
|
||||||
|
wxString message;
|
||||||
|
message.Printf(wxT("%d %s %d %s"), result.index1 + 1, _("of"), wt->GetNumClips(),
|
||||||
|
result.clipStart1 ? _("start") : _("end"));
|
||||||
|
if (result.nFound == 2) {
|
||||||
|
wxString messageAdd;
|
||||||
|
messageAdd.Printf(wxT(" %s %d %s"), _("and"), result.index2 + 1,
|
||||||
|
result.clipStart2 ? _("start") : _("end"));
|
||||||
|
message += messageAdd;
|
||||||
|
}
|
||||||
|
mTrackPanel->MessageForScreenReader(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnSelectPrevClip()
|
||||||
|
{
|
||||||
|
OnSelectClip(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnSelectNextClip()
|
||||||
|
{
|
||||||
|
OnSelectClip(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnSelectClip(bool next)
|
||||||
|
{
|
||||||
|
auto track = mTrackPanel->GetFocusedTrack();
|
||||||
|
|
||||||
|
if (track && track->GetKind() == Track::Wave) {
|
||||||
|
auto wt = static_cast<WaveTrack*>(track);
|
||||||
|
const auto clips = wt->SortedClipArray();
|
||||||
|
double t0 = mViewInfo.selectedRegion.t0();
|
||||||
|
double t1 = mViewInfo.selectedRegion.t1();
|
||||||
|
WaveClip* clip = nullptr;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
auto result = find_if(clips.begin(), clips.end(), [&] (WaveClip* const& clip) {
|
||||||
|
return clip->GetStartTime() == t0; });
|
||||||
|
if (result != clips.end() && (*result)->GetEndTime() != t1 ) {
|
||||||
|
clip = *result;
|
||||||
|
i = result - clips.begin();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto result = find_if(clips.begin(), clips.end(), [&] (WaveClip* const& clip) {
|
||||||
|
return clip->GetStartTime() > t0; });
|
||||||
|
if (result != clips.end()) {
|
||||||
|
clip = *result;
|
||||||
|
i = result - clips.begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto result = find_if(clips.rbegin(), clips.rend(), [&] (WaveClip* const& clip) {
|
||||||
|
return clip->GetStartTime() < t0; });
|
||||||
|
if (result != clips.rend()) {
|
||||||
|
clip = *result;
|
||||||
|
i = static_cast<int>(clips.size()) - 1 - (result - clips.rbegin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clip) {
|
||||||
|
mViewInfo.selectedRegion.setTimes(clip->GetStartTime(), clip->GetEndTime());
|
||||||
|
mTrackPanel->ScrollIntoView(mViewInfo.selectedRegion.t0());
|
||||||
|
ModifyState(false);
|
||||||
|
mTrackPanel->Refresh(false);
|
||||||
|
wxString message;
|
||||||
|
message.Printf(wxT("%d %s %d %s"), i + 1, _("of"), clips.size(), _("selected"));
|
||||||
|
mTrackPanel->MessageForScreenReader(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AudacityProject::OnSelectCursorStoredCursor()
|
void AudacityProject::OnSelectCursorStoredCursor()
|
||||||
{
|
{
|
||||||
if (mCursorPositionHasBeenStored) {
|
if (mCursorPositionHasBeenStored) {
|
||||||
@ -6136,6 +6296,131 @@ void AudacityProject::OnCursorSelEnd()
|
|||||||
mTrackPanel->Refresh(false);
|
mTrackPanel->Refresh(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudacityProject::FoundClipBoundary AudacityProject::FindNextClipBoundary(const WaveTrack* wt, double time)
|
||||||
|
{
|
||||||
|
AudacityProject::FoundClipBoundary result{};
|
||||||
|
|
||||||
|
const auto clips = wt->SortedClipArray();
|
||||||
|
auto resultStart = find_if(clips.begin(), clips.end(), [&] (const WaveClip* const& clip) {
|
||||||
|
return clip->GetStartTime() > time; });
|
||||||
|
auto resultEnd = find_if(clips.begin(), clips.end(), [&] (const WaveClip* const& clip) {
|
||||||
|
return clip->GetEndTime() > time; });
|
||||||
|
|
||||||
|
if (resultStart != clips.end() && resultEnd != clips.end()) {
|
||||||
|
if ((*resultStart)->GetStartTime() < (*resultEnd)->GetEndTime()) {
|
||||||
|
result.nFound = 1;
|
||||||
|
result.time = (*resultStart)->GetStartTime();
|
||||||
|
result.index1 = resultStart - clips.begin();
|
||||||
|
result.clipStart1 = true;
|
||||||
|
}
|
||||||
|
else if ((*resultStart)->GetStartTime() > (*resultEnd)->GetEndTime()) {
|
||||||
|
result.nFound = 1;
|
||||||
|
result.time = (*resultEnd)->GetEndTime();
|
||||||
|
result.index1 = resultEnd - clips.begin();
|
||||||
|
result.clipStart1 = false;
|
||||||
|
}
|
||||||
|
else { // both the end of one clip and the start of the next clip
|
||||||
|
result.nFound = 2;
|
||||||
|
result.time = (*resultEnd)->GetEndTime();
|
||||||
|
result.index1 = resultEnd - clips.begin();
|
||||||
|
result.clipStart1 = false;
|
||||||
|
result.index2 = resultStart - clips.begin();
|
||||||
|
result.clipStart2 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (resultEnd != clips.end()) {
|
||||||
|
result.nFound = 1;
|
||||||
|
result.time = (*resultEnd)->GetEndTime();
|
||||||
|
result.index1 = resultEnd - clips.begin();
|
||||||
|
result.clipStart1 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudacityProject::FoundClipBoundary AudacityProject::FindPrevClipBoundary(const WaveTrack* wt, double time)
|
||||||
|
{
|
||||||
|
AudacityProject::FoundClipBoundary result{};
|
||||||
|
|
||||||
|
const auto clips = wt->SortedClipArray();
|
||||||
|
auto resultStart = find_if(clips.rbegin(), clips.rend(), [&] (const WaveClip* const& clip) {
|
||||||
|
return clip->GetStartTime() < time; });
|
||||||
|
auto resultEnd = find_if(clips.rbegin(), clips.rend(), [&] (const WaveClip* const& clip) {
|
||||||
|
return clip->GetEndTime() < time; });
|
||||||
|
|
||||||
|
if (resultStart != clips.rend() && resultEnd != clips.rend()) {
|
||||||
|
if ((*resultStart)->GetStartTime() > (*resultEnd)->GetEndTime()) {
|
||||||
|
result.nFound = 1;
|
||||||
|
result.time = (*resultStart)->GetStartTime();
|
||||||
|
result.index1 = static_cast<int>(clips.size()) - 1 - (resultStart - clips.rbegin());
|
||||||
|
result.clipStart1 = true;
|
||||||
|
}
|
||||||
|
else if ((*resultStart)->GetStartTime() < (*resultEnd)->GetEndTime()) {
|
||||||
|
result.nFound = 1;
|
||||||
|
result.time = (*resultEnd)->GetEndTime();
|
||||||
|
result.index1 = static_cast<int>(clips.size()) - 1 - (resultEnd - clips.rbegin());
|
||||||
|
result.clipStart1 = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result.nFound = 2; // both the start of one clip and the end of the previous clip
|
||||||
|
result.time = (*resultStart)->GetStartTime();
|
||||||
|
result.index1 = static_cast<int>(clips.size()) - 1 - (resultStart - clips.rbegin());
|
||||||
|
result.clipStart1 = true;
|
||||||
|
result.index2 = static_cast<int>(clips.size()) - 1 - (resultEnd - clips.rbegin());
|
||||||
|
result.clipStart2 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (resultStart != clips.rend()) {
|
||||||
|
result.nFound = 1;
|
||||||
|
result.time = (*resultStart)->GetStartTime();
|
||||||
|
result.index1 = static_cast<int>(clips.size()) - 1 - (resultStart - clips.rbegin());
|
||||||
|
result.clipStart1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnCursorNextClipBoundary()
|
||||||
|
{
|
||||||
|
OnCursorClipBoundary(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnCursorPrevClipBoundary()
|
||||||
|
{
|
||||||
|
OnCursorClipBoundary(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnCursorClipBoundary(bool next)
|
||||||
|
{
|
||||||
|
const auto track = mTrackPanel->GetFocusedTrack();
|
||||||
|
|
||||||
|
if (track && track->GetKind() == Track::Wave) {
|
||||||
|
const auto wt = static_cast<WaveTrack*>(track);
|
||||||
|
if (wt->GetNumClips()) {
|
||||||
|
auto result = next ? FindNextClipBoundary(wt, mViewInfo.selectedRegion.t0()) :
|
||||||
|
FindPrevClipBoundary(wt, mViewInfo.selectedRegion.t0());
|
||||||
|
|
||||||
|
if (result.nFound > 0) {
|
||||||
|
mViewInfo.selectedRegion.setTimes(result.time, result.time);
|
||||||
|
ModifyState(false);
|
||||||
|
mTrackPanel->ScrollIntoView(mViewInfo.selectedRegion.t0());
|
||||||
|
mTrackPanel->Refresh(false);
|
||||||
|
|
||||||
|
wxString message;
|
||||||
|
message.Printf(wxT("%d %s %d %s"), result.index1 + 1, _("of"), wt->GetNumClips(),
|
||||||
|
result.clipStart1 ? _("start") : _("end"));
|
||||||
|
if (result.nFound == 2) {
|
||||||
|
wxString messageAdd;
|
||||||
|
messageAdd.Printf(wxT(" %s %d %s"), _("and"), result.index2 + 1,
|
||||||
|
result.clipStart2 ? _("start") : _("end"));
|
||||||
|
message += messageAdd;
|
||||||
|
}
|
||||||
|
mTrackPanel->MessageForScreenReader(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AudacityProject::HandleAlign(int index, bool moveSel)
|
void AudacityProject::HandleAlign(int index, bool moveSel)
|
||||||
{
|
{
|
||||||
TrackListIterator iter(GetTracks());
|
TrackListIterator iter(GetTracks());
|
||||||
@ -7085,6 +7370,41 @@ void AudacityProject::OnExpandAllTracks()
|
|||||||
RedrawProject();
|
RedrawProject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnPanTracks(float PanValue)
|
||||||
|
{
|
||||||
|
TrackListIterator iter(GetTracks());
|
||||||
|
Track *t = iter.First();
|
||||||
|
|
||||||
|
// count selected wave tracks
|
||||||
|
int count =0;
|
||||||
|
while (t)
|
||||||
|
{
|
||||||
|
if( t->GetKind() == Track::Wave && t->GetSelected() )
|
||||||
|
count++;
|
||||||
|
t = iter.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// iter through them, all if none selected.
|
||||||
|
t = iter.First();
|
||||||
|
while (t)
|
||||||
|
{
|
||||||
|
if( t->GetKind() == Track::Wave && ((count==0) || t->GetSelected()) ){
|
||||||
|
WaveTrack *left = (WaveTrack *)t;
|
||||||
|
left->SetPan( PanValue );
|
||||||
|
}
|
||||||
|
t = iter.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
ModifyState(true);
|
||||||
|
RedrawProject();
|
||||||
|
if (mMixerBoard)
|
||||||
|
mMixerBoard->UpdatePan();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnPanLeft(){ OnPanTracks( -1.0);}
|
||||||
|
void AudacityProject::OnPanRight(){ OnPanTracks( 1.0);}
|
||||||
|
void AudacityProject::OnPanCenter(){ OnPanTracks( 0.0);}
|
||||||
|
|
||||||
|
|
||||||
void AudacityProject::OnMuteAllTracks()
|
void AudacityProject::OnMuteAllTracks()
|
||||||
{
|
{
|
||||||
|
27
src/Menus.h
27
src/Menus.h
@ -160,6 +160,9 @@ void OnSelExtendRight(const wxEvent * evt);
|
|||||||
void OnSelContractLeft(const wxEvent * evt);
|
void OnSelContractLeft(const wxEvent * evt);
|
||||||
void OnSelContractRight(const wxEvent * evt);
|
void OnSelContractRight(const wxEvent * evt);
|
||||||
|
|
||||||
|
void OnClipLeft();
|
||||||
|
void OnClipRight();
|
||||||
|
|
||||||
void OnCursorShortJumpLeft();
|
void OnCursorShortJumpLeft();
|
||||||
void OnCursorShortJumpRight();
|
void OnCursorShortJumpRight();
|
||||||
void OnCursorLongJumpLeft();
|
void OnCursorLongJumpLeft();
|
||||||
@ -282,6 +285,12 @@ void OnNextLowerPeakFrequency();
|
|||||||
#endif
|
#endif
|
||||||
void OnSelectCursorEnd();
|
void OnSelectCursorEnd();
|
||||||
void OnSelectStartCursor();
|
void OnSelectStartCursor();
|
||||||
|
void OnSelectPrevClipBoundaryToCursor();
|
||||||
|
void OnSelectCursorToNextClipBoundary();
|
||||||
|
void OnSelectClipBoundary(bool next);
|
||||||
|
void OnSelectPrevClip();
|
||||||
|
void OnSelectNextClip();
|
||||||
|
void OnSelectClip(bool next);
|
||||||
void OnSelectCursorStoredCursor();
|
void OnSelectCursorStoredCursor();
|
||||||
void OnSelectSyncLockSel();
|
void OnSelectSyncLockSel();
|
||||||
void OnSelectAllTracks();
|
void OnSelectAllTracks();
|
||||||
@ -302,6 +311,11 @@ void OnGoSelEnd();
|
|||||||
void OnExpandAllTracks();
|
void OnExpandAllTracks();
|
||||||
void OnCollapseAllTracks();
|
void OnCollapseAllTracks();
|
||||||
|
|
||||||
|
void OnPanTracks(float PanValue);
|
||||||
|
void OnPanLeft();
|
||||||
|
void OnPanRight();
|
||||||
|
void OnPanCenter();
|
||||||
|
|
||||||
void OnMuteAllTracks();
|
void OnMuteAllTracks();
|
||||||
void OnUnMuteAllTracks();
|
void OnUnMuteAllTracks();
|
||||||
|
|
||||||
@ -375,6 +389,19 @@ void OnCursorTrackStart();
|
|||||||
void OnCursorTrackEnd();
|
void OnCursorTrackEnd();
|
||||||
void OnCursorSelStart();
|
void OnCursorSelStart();
|
||||||
void OnCursorSelEnd();
|
void OnCursorSelEnd();
|
||||||
|
typedef struct FoundClipBoundary {
|
||||||
|
int nFound; // 0, 1, or 2
|
||||||
|
double time;
|
||||||
|
int index1;
|
||||||
|
bool clipStart1;
|
||||||
|
int index2;
|
||||||
|
bool clipStart2;
|
||||||
|
} FoundClipBoundary;
|
||||||
|
FoundClipBoundary FindNextClipBoundary(const WaveTrack* wt, double time);
|
||||||
|
FoundClipBoundary FindPrevClipBoundary(const WaveTrack* wt, double time);
|
||||||
|
void OnCursorNextClipBoundary();
|
||||||
|
void OnCursorPrevClipBoundary();
|
||||||
|
void OnCursorClipBoundary(bool next);
|
||||||
|
|
||||||
void OnAlignNoSync(int index);
|
void OnAlignNoSync(int index);
|
||||||
void OnAlign(int index);
|
void OnAlign(int index);
|
||||||
|
@ -1227,10 +1227,18 @@ void MixerBoard::UpdateSolo(const PlayableTrack* pTrack /*= NULL*/) // NULL mean
|
|||||||
|
|
||||||
void MixerBoard::UpdatePan(const PlayableTrack* pTrack)
|
void MixerBoard::UpdatePan(const PlayableTrack* pTrack)
|
||||||
{
|
{
|
||||||
MixerTrackCluster* pMixerTrackCluster;
|
if (pTrack == NULL)
|
||||||
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
|
{
|
||||||
if (pMixerTrackCluster)
|
for (unsigned int i = 0; i < mMixerTrackClusters.GetCount(); i++)
|
||||||
pMixerTrackCluster->UpdatePan();
|
mMixerTrackClusters[i]->UpdatePan();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MixerTrackCluster* pMixerTrackCluster;
|
||||||
|
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
|
||||||
|
if (pMixerTrackCluster)
|
||||||
|
pMixerTrackCluster->UpdatePan();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MixerBoard::UpdateGain(const PlayableTrack* pTrack)
|
void MixerBoard::UpdateGain(const PlayableTrack* pTrack)
|
||||||
|
@ -236,7 +236,7 @@ public:
|
|||||||
void UpdateName(const PlayableTrack* pTrack);
|
void UpdateName(const PlayableTrack* pTrack);
|
||||||
void UpdateMute(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks.
|
void UpdateMute(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks.
|
||||||
void UpdateSolo(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks.
|
void UpdateSolo(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks.
|
||||||
void UpdatePan(const PlayableTrack* pTrack);
|
void UpdatePan(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks.
|
||||||
void UpdateGain(const PlayableTrack* pTrack);
|
void UpdateGain(const PlayableTrack* pTrack);
|
||||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||||
void UpdateVelocity(const PlayableTrack* pTrack);
|
void UpdateVelocity(const PlayableTrack* pTrack);
|
||||||
|
@ -609,7 +609,7 @@ void Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
auto file = mDirManager->CopyBlockFile(block.f);
|
auto file = mDirManager->CopyBlockFile(block.f);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
wxASSERT(false); // TODO: Handle this better, alert the user of failure.
|
wxASSERT(false); // TODO: Handle this better, alert the user of failure.
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
newBlock.push_back(SeqBlock(file, block.start + s));
|
newBlock.push_back(SeqBlock(file, block.start + s));
|
||||||
@ -743,7 +743,7 @@ void Sequence::AppendBlock
|
|||||||
if (!newBlock.f) {
|
if (!newBlock.f) {
|
||||||
/// \todo Error Could not paste! (Out of disk space?)
|
/// \todo Error Could not paste! (Out of disk space?)
|
||||||
wxASSERT(false); // TODO: Handle this better, alert the user of failure.
|
wxASSERT(false); // TODO: Handle this better, alert the user of failure.
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mBlock.push_back(newBlock);
|
mBlock.push_back(newBlock);
|
||||||
|
@ -371,7 +371,7 @@ BEGIN_EVENT_TABLE(TrackPanel, OverlayPanel)
|
|||||||
EVT_MENU_RANGE(On16BitID, OnFloatID, TrackPanel::OnFormatChange)
|
EVT_MENU_RANGE(On16BitID, OnFloatID, TrackPanel::OnFormatChange)
|
||||||
EVT_MENU(OnRateOtherID, TrackPanel::OnRateOther)
|
EVT_MENU(OnRateOtherID, TrackPanel::OnRateOther)
|
||||||
EVT_MENU(OnSwapChannelsID, TrackPanel::OnSwapChannels)
|
EVT_MENU(OnSwapChannelsID, TrackPanel::OnSwapChannels)
|
||||||
EVT_MENU(OnSplitStereoID, TrackPanel::OnSplitStereoMono)
|
EVT_MENU(OnSplitStereoID, TrackPanel::OnSplitStereo)
|
||||||
EVT_MENU(OnSplitStereoMonoID, TrackPanel::OnSplitStereoMono)
|
EVT_MENU(OnSplitStereoMonoID, TrackPanel::OnSplitStereoMono)
|
||||||
EVT_MENU(OnMergeStereoID, TrackPanel::OnMergeStereo)
|
EVT_MENU(OnMergeStereoID, TrackPanel::OnMergeStereo)
|
||||||
|
|
||||||
@ -630,7 +630,10 @@ void TrackPanel::BuildMenus(void)
|
|||||||
mWaveTrackMenu->Append(OnMergeStereoID, _("Ma&ke Stereo Track"));
|
mWaveTrackMenu->Append(OnMergeStereoID, _("Ma&ke Stereo Track"));
|
||||||
mWaveTrackMenu->Append(OnSwapChannelsID, _("Swap Stereo &Channels"));
|
mWaveTrackMenu->Append(OnSwapChannelsID, _("Swap Stereo &Channels"));
|
||||||
mWaveTrackMenu->Append(OnSplitStereoID, _("Spl&it Stereo Track"));
|
mWaveTrackMenu->Append(OnSplitStereoID, _("Spl&it Stereo Track"));
|
||||||
// mWaveTrackMenu->Append(OnSplitStereoMonoID, _("Split Stereo to Mo&no"));
|
// DA: Uses split stereo track and then drag pan sliders for split-stereo-to-mono
|
||||||
|
#ifndef EXPERIMENTAL_DA
|
||||||
|
mWaveTrackMenu->Append(OnSplitStereoMonoID, _("Split Stereo to Mo&no"));
|
||||||
|
#endif
|
||||||
mWaveTrackMenu->AppendSeparator();
|
mWaveTrackMenu->AppendSeparator();
|
||||||
|
|
||||||
mWaveTrackMenu->Append(0, _("&Format"), (mFormatMenu = formatMenu.release()));
|
mWaveTrackMenu->Append(0, _("&Format"), (mFormatMenu = formatMenu.release()));
|
||||||
@ -3479,89 +3482,18 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
|
|||||||
if (mCapturedClip == NULL)
|
if (mCapturedClip == NULL)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The captured clip is the focus, but we need to create a list
|
|
||||||
// of all clips that have to move, also...
|
|
||||||
|
|
||||||
mCapturedClipArray.clear();
|
mCapturedTrack = vt;
|
||||||
|
CreateListOfCapturedClips(clickTime);
|
||||||
// First, if click was in selection, capture selected clips; otherwise
|
|
||||||
// just the clicked-on clip
|
|
||||||
if (mCapturedClipIsSelection) {
|
|
||||||
TrackListIterator iter(GetTracks());
|
|
||||||
for (Track *t = iter.First(); t; t = iter.Next()) {
|
|
||||||
if (t->GetSelected()) {
|
|
||||||
AddClipsToCaptured(t, true);
|
|
||||||
if (t->GetKind() != Track::Wave)
|
|
||||||
mTrackExclusions.push_back(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mCapturedClipArray.push_back(TrackClip(vt, mCapturedClip));
|
|
||||||
|
|
||||||
// Check for stereo partner
|
|
||||||
Track *partner = vt->GetLink();
|
|
||||||
WaveTrack *wt;
|
|
||||||
if (mCapturedClip &&
|
|
||||||
// Assume linked track is wave or null
|
|
||||||
nullptr != (wt = static_cast<WaveTrack*>(partner))) {
|
|
||||||
WaveClip *const clip =
|
|
||||||
FindClipAtTime(wt,
|
|
||||||
mViewInfo->PositionToTime(event.m_x, GetLeftOffset()));
|
|
||||||
if (clip)
|
|
||||||
mCapturedClipArray.push_back(TrackClip(partner, clip));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, if sync-lock is enabled, capture any clip that's linked to a
|
|
||||||
// captured clip.
|
|
||||||
if (GetProject()->IsSyncLocked()) {
|
|
||||||
// AWD: mCapturedClipArray expands as the loop runs, so newly-added
|
|
||||||
// clips are considered (the effect is like recursion and terminates
|
|
||||||
// because AddClipsToCaptured doesn't add duplicate clips); to remove
|
|
||||||
// this behavior just store the array size beforehand.
|
|
||||||
for (unsigned int i = 0; i < mCapturedClipArray.size(); ++i) {
|
|
||||||
// Capture based on tracks that have clips -- that means we
|
|
||||||
// don't capture based on links to label tracks for now (until
|
|
||||||
// we can treat individual labels as clips)
|
|
||||||
if (mCapturedClipArray[i].clip) {
|
|
||||||
// Iterate over sync-lock group tracks.
|
|
||||||
SyncLockedTracksIterator git(GetTracks());
|
|
||||||
for (Track *t = git.StartWith(mCapturedClipArray[i].track);
|
|
||||||
t; t = git.Next() )
|
|
||||||
{
|
|
||||||
AddClipsToCaptured(t,
|
|
||||||
mCapturedClipArray[i].clip->GetStartTime(),
|
|
||||||
mCapturedClipArray[i].clip->GetEndTime() );
|
|
||||||
if (t->GetKind() != Track::Wave)
|
|
||||||
mTrackExclusions.push_back(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef USE_MIDI
|
|
||||||
// Capture additional clips from NoteTracks
|
|
||||||
Track *nt = mCapturedClipArray[i].track;
|
|
||||||
if (nt->GetKind() == Track::Note) {
|
|
||||||
// Iterate over sync-lock group tracks.
|
|
||||||
SyncLockedTracksIterator git(GetTracks());
|
|
||||||
for (Track *t = git.StartWith(nt); t; t = git.Next())
|
|
||||||
{
|
|
||||||
AddClipsToCaptured(t, nt->GetStartTime(), nt->GetEndTime());
|
|
||||||
if (t->GetKind() != Track::Wave)
|
|
||||||
mTrackExclusions.push_back(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
mCapturedClip = NULL;
|
mCapturedClip = NULL;
|
||||||
mCapturedClipArray.clear();
|
mCapturedClipArray.clear();
|
||||||
|
mCapturedTrack = vt;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive;
|
mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive;
|
||||||
|
|
||||||
mCapturedTrack = vt;
|
|
||||||
mCapturedRect = rect;
|
mCapturedRect = rect;
|
||||||
|
|
||||||
mMouseClickX = event.m_x;
|
mMouseClickX = event.m_x;
|
||||||
@ -3587,6 +3519,83 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
|
|||||||
mMouseCapture = IsSliding;
|
mMouseCapture = IsSliding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TrackPanel::CreateListOfCapturedClips(double clickTime)
|
||||||
|
{
|
||||||
|
// The captured clip is the focus, but we need to create a list
|
||||||
|
// of all clips that have to move, also...
|
||||||
|
|
||||||
|
mCapturedClipArray.clear();
|
||||||
|
|
||||||
|
// First, if click was in selection, capture selected clips; otherwise
|
||||||
|
// just the clicked-on clip
|
||||||
|
if (mCapturedClipIsSelection) {
|
||||||
|
TrackListIterator iter(GetTracks());
|
||||||
|
for (Track *t = iter.First(); t; t = iter.Next()) {
|
||||||
|
if (t->GetSelected()) {
|
||||||
|
AddClipsToCaptured(t, true);
|
||||||
|
if (t->GetKind() != Track::Wave)
|
||||||
|
mTrackExclusions.push_back(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mCapturedClipArray.push_back(TrackClip(mCapturedTrack, mCapturedClip));
|
||||||
|
|
||||||
|
// Check for stereo partner
|
||||||
|
Track *partner = mCapturedTrack->GetLink();
|
||||||
|
WaveTrack *wt;
|
||||||
|
if (mCapturedClip &&
|
||||||
|
// Assume linked track is wave or null
|
||||||
|
nullptr != (wt = static_cast<WaveTrack*>(partner))) {
|
||||||
|
WaveClip *const clip = FindClipAtTime(wt, clickTime);
|
||||||
|
|
||||||
|
if (clip)
|
||||||
|
mCapturedClipArray.push_back(TrackClip(partner, clip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, if sync-lock is enabled, capture any clip that's linked to a
|
||||||
|
// captured clip.
|
||||||
|
if (GetProject()->IsSyncLocked()) {
|
||||||
|
// AWD: mCapturedClipArray expands as the loop runs, so newly-added
|
||||||
|
// clips are considered (the effect is like recursion and terminates
|
||||||
|
// because AddClipsToCaptured doesn't add duplicate clips); to remove
|
||||||
|
// this behavior just store the array size beforehand.
|
||||||
|
for (unsigned int i = 0; i < mCapturedClipArray.size(); ++i) {
|
||||||
|
// Capture based on tracks that have clips -- that means we
|
||||||
|
// don't capture based on links to label tracks for now (until
|
||||||
|
// we can treat individual labels as clips)
|
||||||
|
if (mCapturedClipArray[i].clip) {
|
||||||
|
// Iterate over sync-lock group tracks.
|
||||||
|
SyncLockedTracksIterator git(GetTracks());
|
||||||
|
for (Track *t = git.StartWith(mCapturedClipArray[i].track);
|
||||||
|
t; t = git.Next() )
|
||||||
|
{
|
||||||
|
AddClipsToCaptured(t,
|
||||||
|
mCapturedClipArray[i].clip->GetStartTime(),
|
||||||
|
mCapturedClipArray[i].clip->GetEndTime() );
|
||||||
|
if (t->GetKind() != Track::Wave)
|
||||||
|
mTrackExclusions.push_back(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef USE_MIDI
|
||||||
|
// Capture additional clips from NoteTracks
|
||||||
|
Track *nt = mCapturedClipArray[i].track;
|
||||||
|
if (nt->GetKind() == Track::Note) {
|
||||||
|
// Iterate over sync-lock group tracks.
|
||||||
|
SyncLockedTracksIterator git(GetTracks());
|
||||||
|
for (Track *t = git.StartWith(nt); t; t = git.Next())
|
||||||
|
{
|
||||||
|
AddClipsToCaptured(t, nt->GetStartTime(), nt->GetEndTime());
|
||||||
|
if (t->GetKind() != Track::Wave)
|
||||||
|
mTrackExclusions.push_back(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helper for the above, adds a track's clips to mCapturedClipArray (eliminates
|
// Helper for the above, adds a track's clips to mCapturedClipArray (eliminates
|
||||||
// duplication of this logic)
|
// duplication of this logic)
|
||||||
void TrackPanel::AddClipsToCaptured(Track *t, bool withinSelection)
|
void TrackPanel::AddClipsToCaptured(Track *t, bool withinSelection)
|
||||||
@ -3877,6 +3886,24 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
|
|||||||
|
|
||||||
mHSlideAmount = desiredSlideAmount;
|
mHSlideAmount = desiredSlideAmount;
|
||||||
|
|
||||||
|
DoSlideHorizontal();
|
||||||
|
|
||||||
|
|
||||||
|
if (mCapturedClipIsSelection) {
|
||||||
|
// Slide the selection, too
|
||||||
|
mViewInfo->selectedRegion.move(mHSlideAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slidVertically) {
|
||||||
|
// NEW origin
|
||||||
|
mHSlideAmount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Refresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackPanel::DoSlideHorizontal()
|
||||||
|
{
|
||||||
#ifdef USE_MIDI
|
#ifdef USE_MIDI
|
||||||
if (mCapturedClipArray.size())
|
if (mCapturedClipArray.size())
|
||||||
#else
|
#else
|
||||||
@ -3947,18 +3974,55 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
|
|||||||
if (link)
|
if (link)
|
||||||
link->Offset(mHSlideAmount);
|
link->Offset(mHSlideAmount);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mCapturedClipIsSelection) {
|
void TrackPanel::OnClipMove(bool right)
|
||||||
// Slide the selection, too
|
{
|
||||||
mViewInfo->selectedRegion.move(mHSlideAmount);
|
auto track = GetFocusedTrack();
|
||||||
|
|
||||||
|
|
||||||
|
// just dealing with clips in wave tracks for the moment. Note tracks??
|
||||||
|
if (track && track->GetKind() == Track::Wave) {
|
||||||
|
auto wt = static_cast<WaveTrack*>(track);
|
||||||
|
mCapturedClip = wt->GetClipAtTime(mViewInfo->selectedRegion.t0());
|
||||||
|
if (mCapturedClip == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mCapturedTrack = track;
|
||||||
|
mCapturedClipIsSelection = track->GetSelected() && !mViewInfo->selectedRegion.isPoint();
|
||||||
|
mTrackExclusions.clear();
|
||||||
|
|
||||||
|
CreateListOfCapturedClips(mViewInfo->selectedRegion.t0());
|
||||||
|
|
||||||
|
double desiredSlideAmount = mViewInfo->OffsetTimeByPixels(0.0, 1);
|
||||||
|
|
||||||
|
// set it to a sample point, and minimum of 1 sample point
|
||||||
|
double nSamples = rint(wt->GetRate() * desiredSlideAmount);
|
||||||
|
nSamples = std::max(nSamples, 1.0);
|
||||||
|
desiredSlideAmount = nSamples / wt->GetRate();
|
||||||
|
|
||||||
|
if (!right)
|
||||||
|
desiredSlideAmount *= -1;
|
||||||
|
mHSlideAmount = desiredSlideAmount;
|
||||||
|
DoSlideHorizontal();
|
||||||
|
|
||||||
|
// update t0 and t1. There is the possibility that the updated
|
||||||
|
// t0 may no longer be within the clip due to rounding errors,
|
||||||
|
// so t0 is adjusted so that it is.
|
||||||
|
double newT0 = mViewInfo->selectedRegion.t0() + mHSlideAmount;
|
||||||
|
if (newT0 < mCapturedClip->GetStartTime())
|
||||||
|
newT0 = mCapturedClip->GetStartTime();
|
||||||
|
if (newT0 > mCapturedClip->GetEndTime())
|
||||||
|
newT0 = mCapturedClip->GetEndTime();
|
||||||
|
double diff = mViewInfo->selectedRegion.t1() - mViewInfo->selectedRegion.t0();
|
||||||
|
mViewInfo->selectedRegion.setTimes(newT0, newT0 + diff);
|
||||||
|
|
||||||
|
ScrollIntoView(mViewInfo->selectedRegion.t0());
|
||||||
|
Refresh(false);
|
||||||
|
|
||||||
|
if (mHSlideAmount == 0.0)
|
||||||
|
MessageForScreenReader( _("clip not moved"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slidVertically) {
|
|
||||||
// NEW origin
|
|
||||||
mHSlideAmount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Refresh(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -8064,10 +8128,11 @@ void TrackPanel::SplitStereo(bool stereo)
|
|||||||
{
|
{
|
||||||
wxASSERT(mPopupMenuTarget);
|
wxASSERT(mPopupMenuTarget);
|
||||||
|
|
||||||
if (!stereo){
|
if (stereo){
|
||||||
mPopupMenuTarget->SetPanFromChannelType();
|
mPopupMenuTarget->SetPanFromChannelType();
|
||||||
mPopupMenuTarget->SetChannel(Track::MonoChannel);
|
|
||||||
}
|
}
|
||||||
|
mPopupMenuTarget->SetChannel(Track::MonoChannel);
|
||||||
|
|
||||||
|
|
||||||
// Assume partner is present, and is wave
|
// Assume partner is present, and is wave
|
||||||
auto partner = static_cast<WaveTrack*>(mPopupMenuTarget->GetLink());
|
auto partner = static_cast<WaveTrack*>(mPopupMenuTarget->GetLink());
|
||||||
@ -8086,10 +8151,11 @@ void TrackPanel::SplitStereo(bool stereo)
|
|||||||
if (partner)
|
if (partner)
|
||||||
{
|
{
|
||||||
partner->SetName(mPopupMenuTarget->GetName());
|
partner->SetName(mPopupMenuTarget->GetName());
|
||||||
if (!stereo){
|
if (stereo){
|
||||||
partner->SetPanFromChannelType();
|
partner->SetPanFromChannelType();
|
||||||
partner->SetChannel(Track::MonoChannel); // Keep original stereo track name.
|
|
||||||
}
|
}
|
||||||
|
partner->SetChannel(Track::MonoChannel); // Keep original stereo track name.
|
||||||
|
|
||||||
|
|
||||||
//On Demand - have each channel add it's own.
|
//On Demand - have each channel add it's own.
|
||||||
if (ODManager::IsInstanceCreated() && partner->GetKind() == Track::Wave)
|
if (ODManager::IsInstanceCreated() && partner->GetKind() == Track::Wave)
|
||||||
|
@ -252,6 +252,8 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
|||||||
// (ignoring any fisheye)
|
// (ignoring any fisheye)
|
||||||
virtual double GetScreenEndTime() const;
|
virtual double GetScreenEndTime() const;
|
||||||
|
|
||||||
|
virtual void OnClipMove(bool right);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual MixerBoard* GetMixerBoard();
|
virtual MixerBoard* GetMixerBoard();
|
||||||
/** @brief Populates the track pop-down menu with the common set of
|
/** @brief Populates the track pop-down menu with the common set of
|
||||||
@ -377,6 +379,8 @@ protected:
|
|||||||
virtual void HandleSlide(wxMouseEvent & event);
|
virtual void HandleSlide(wxMouseEvent & event);
|
||||||
virtual void StartSlide(wxMouseEvent &event);
|
virtual void StartSlide(wxMouseEvent &event);
|
||||||
virtual void DoSlide(wxMouseEvent &event);
|
virtual void DoSlide(wxMouseEvent &event);
|
||||||
|
virtual void DoSlideHorizontal();
|
||||||
|
virtual void CreateListOfCapturedClips(double clickTime);
|
||||||
virtual void AddClipsToCaptured(Track *t, bool withinSelection);
|
virtual void AddClipsToCaptured(Track *t, bool withinSelection);
|
||||||
virtual void AddClipsToCaptured(Track *t, double t0, double t1);
|
virtual void AddClipsToCaptured(Track *t, double t0, double t1);
|
||||||
|
|
||||||
|
@ -2228,6 +2228,17 @@ WaveClip* WaveTrack::GetClipAtSample(sampleCount sample)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WaveClip* WaveTrack::GetClipAtTime(double time)
|
||||||
|
{
|
||||||
|
// When the time is both the end of a clip and the start of the next clip, the
|
||||||
|
// latter clip is returned.
|
||||||
|
const auto clips = SortedClipArray();
|
||||||
|
auto result = find_if(clips.rbegin(), clips.rend(), [&] (WaveClip* const& clip) {
|
||||||
|
return time >= clip->GetStartTime() && time <= clip->GetEndTime(); });
|
||||||
|
|
||||||
|
return result != clips.rend() ? *result : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Envelope* WaveTrack::GetEnvelopeAtX(int xcoord)
|
Envelope* WaveTrack::GetEnvelopeAtX(int xcoord)
|
||||||
{
|
{
|
||||||
WaveClip* clip = GetClipAtX(xcoord);
|
WaveClip* clip = GetClipAtX(xcoord);
|
||||||
|
@ -276,6 +276,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack {
|
|||||||
Envelope* GetEnvelopeAtX(int xcoord);
|
Envelope* GetEnvelopeAtX(int xcoord);
|
||||||
|
|
||||||
WaveClip* GetClipAtSample(sampleCount sample);
|
WaveClip* GetClipAtSample(sampleCount sample);
|
||||||
|
WaveClip* GetClipAtTime(double time);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Getting information about the track's internal block sizes
|
// Getting information about the track's internal block sizes
|
||||||
|
@ -164,7 +164,11 @@ void GUIPrefs::PopulateOrExchange(ShuttleGui & S)
|
|||||||
|
|
||||||
S.StartStatic(_("Theme"));
|
S.StartStatic(_("Theme"));
|
||||||
{
|
{
|
||||||
|
#ifdef EXPERIMENTAL_DA
|
||||||
S.StartRadioButtonGroup(wxT("/GUI/Theme"), wxT("dark"));
|
S.StartRadioButtonGroup(wxT("/GUI/Theme"), wxT("dark"));
|
||||||
|
#else
|
||||||
|
S.StartRadioButtonGroup(wxT("/GUI/Theme"), wxT("classic"));
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
S.TieRadioButton(_("Classic"),
|
S.TieRadioButton(_("Classic"),
|
||||||
wxT("classic"));
|
wxT("classic"));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user