mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-05 22:28:57 +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
|
||||
//on each line. If the second token is not a number, we treat
|
||||
//it as a single-value label.
|
||||
bool error = false;
|
||||
for (int index = 0; index < lines;) {
|
||||
try {
|
||||
// Let LabelStruct::Import advance index
|
||||
LabelStruct l { LabelStruct::Import(in, index) };
|
||||
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();
|
||||
}
|
||||
|
||||
|
458
src/Menus.cpp
458
src/Menus.cpp
@ -35,6 +35,7 @@ simplifies construction of menu items.
|
||||
|
||||
#include <cfloat>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#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->EndSubMenu();
|
||||
|
||||
c->AddSeparator();
|
||||
|
||||
c->AddItem(wxT("EditMetaData"), _("Me&tadata..."), FN(OnEditMetadata));
|
||||
c->AddSeparator();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
c->BeginSubMenu(_("La&bels"));
|
||||
@ -562,70 +558,7 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
|
||||
c->EndSubMenu();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* 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();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
c->AddItem(wxT("EditMetaData"), _("Me&tadata..."), FN(OnEditMetadata));
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -645,6 +578,104 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
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();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@ -817,6 +848,11 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
c->AddItem(wxT("CursTrackStart"), _("Track &Start"), FN(OnCursorTrackStart), wxT("J"));
|
||||
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("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->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();
|
||||
|
||||
wxArrayString alignLabelsNoSync;
|
||||
@ -1260,6 +1303,9 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
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("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("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 );
|
||||
}
|
||||
|
||||
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.
|
||||
//If playing/recording is happening, it sets the left selection at
|
||||
//the current play position.
|
||||
@ -5309,6 +5365,110 @@ void AudacityProject::OnSelectStartCursor()
|
||||
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()
|
||||
{
|
||||
if (mCursorPositionHasBeenStored) {
|
||||
@ -6136,6 +6296,131 @@ void AudacityProject::OnCursorSelEnd()
|
||||
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)
|
||||
{
|
||||
TrackListIterator iter(GetTracks());
|
||||
@ -7085,6 +7370,41 @@ void AudacityProject::OnExpandAllTracks()
|
||||
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()
|
||||
{
|
||||
|
27
src/Menus.h
27
src/Menus.h
@ -160,6 +160,9 @@ void OnSelExtendRight(const wxEvent * evt);
|
||||
void OnSelContractLeft(const wxEvent * evt);
|
||||
void OnSelContractRight(const wxEvent * evt);
|
||||
|
||||
void OnClipLeft();
|
||||
void OnClipRight();
|
||||
|
||||
void OnCursorShortJumpLeft();
|
||||
void OnCursorShortJumpRight();
|
||||
void OnCursorLongJumpLeft();
|
||||
@ -282,6 +285,12 @@ void OnNextLowerPeakFrequency();
|
||||
#endif
|
||||
void OnSelectCursorEnd();
|
||||
void OnSelectStartCursor();
|
||||
void OnSelectPrevClipBoundaryToCursor();
|
||||
void OnSelectCursorToNextClipBoundary();
|
||||
void OnSelectClipBoundary(bool next);
|
||||
void OnSelectPrevClip();
|
||||
void OnSelectNextClip();
|
||||
void OnSelectClip(bool next);
|
||||
void OnSelectCursorStoredCursor();
|
||||
void OnSelectSyncLockSel();
|
||||
void OnSelectAllTracks();
|
||||
@ -302,6 +311,11 @@ void OnGoSelEnd();
|
||||
void OnExpandAllTracks();
|
||||
void OnCollapseAllTracks();
|
||||
|
||||
void OnPanTracks(float PanValue);
|
||||
void OnPanLeft();
|
||||
void OnPanRight();
|
||||
void OnPanCenter();
|
||||
|
||||
void OnMuteAllTracks();
|
||||
void OnUnMuteAllTracks();
|
||||
|
||||
@ -375,6 +389,19 @@ void OnCursorTrackStart();
|
||||
void OnCursorTrackEnd();
|
||||
void OnCursorSelStart();
|
||||
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 OnAlign(int index);
|
||||
|
@ -1227,10 +1227,18 @@ void MixerBoard::UpdateSolo(const PlayableTrack* pTrack /*= NULL*/) // NULL mean
|
||||
|
||||
void MixerBoard::UpdatePan(const PlayableTrack* pTrack)
|
||||
{
|
||||
MixerTrackCluster* pMixerTrackCluster;
|
||||
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
|
||||
if (pMixerTrackCluster)
|
||||
pMixerTrackCluster->UpdatePan();
|
||||
if (pTrack == NULL)
|
||||
{
|
||||
for (unsigned int i = 0; i < mMixerTrackClusters.GetCount(); i++)
|
||||
mMixerTrackClusters[i]->UpdatePan();
|
||||
}
|
||||
else
|
||||
{
|
||||
MixerTrackCluster* pMixerTrackCluster;
|
||||
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
|
||||
if (pMixerTrackCluster)
|
||||
pMixerTrackCluster->UpdatePan();
|
||||
}
|
||||
}
|
||||
|
||||
void MixerBoard::UpdateGain(const PlayableTrack* pTrack)
|
||||
|
@ -236,7 +236,7 @@ public:
|
||||
void UpdateName(const PlayableTrack* pTrack);
|
||||
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 UpdatePan(const PlayableTrack* pTrack);
|
||||
void UpdatePan(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks.
|
||||
void UpdateGain(const PlayableTrack* pTrack);
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
void UpdateVelocity(const PlayableTrack* pTrack);
|
||||
|
@ -609,7 +609,7 @@ void Sequence::Paste(sampleCount s, const Sequence *src)
|
||||
auto file = mDirManager->CopyBlockFile(block.f);
|
||||
if (!file) {
|
||||
wxASSERT(false); // TODO: Handle this better, alert the user of failure.
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
newBlock.push_back(SeqBlock(file, block.start + s));
|
||||
@ -743,7 +743,7 @@ void Sequence::AppendBlock
|
||||
if (!newBlock.f) {
|
||||
/// \todo Error Could not paste! (Out of disk space?)
|
||||
wxASSERT(false); // TODO: Handle this better, alert the user of failure.
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
mBlock.push_back(newBlock);
|
||||
|
@ -371,7 +371,7 @@ BEGIN_EVENT_TABLE(TrackPanel, OverlayPanel)
|
||||
EVT_MENU_RANGE(On16BitID, OnFloatID, TrackPanel::OnFormatChange)
|
||||
EVT_MENU(OnRateOtherID, TrackPanel::OnRateOther)
|
||||
EVT_MENU(OnSwapChannelsID, TrackPanel::OnSwapChannels)
|
||||
EVT_MENU(OnSplitStereoID, TrackPanel::OnSplitStereoMono)
|
||||
EVT_MENU(OnSplitStereoID, TrackPanel::OnSplitStereo)
|
||||
EVT_MENU(OnSplitStereoMonoID, TrackPanel::OnSplitStereoMono)
|
||||
EVT_MENU(OnMergeStereoID, TrackPanel::OnMergeStereo)
|
||||
|
||||
@ -630,7 +630,10 @@ void TrackPanel::BuildMenus(void)
|
||||
mWaveTrackMenu->Append(OnMergeStereoID, _("Ma&ke Stereo Track"));
|
||||
mWaveTrackMenu->Append(OnSwapChannelsID, _("Swap Stereo &Channels"));
|
||||
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->Append(0, _("&Format"), (mFormatMenu = formatMenu.release()));
|
||||
@ -3479,89 +3482,18 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
|
||||
if (mCapturedClip == NULL)
|
||||
return;
|
||||
}
|
||||
// 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(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
|
||||
}
|
||||
}
|
||||
mCapturedTrack = vt;
|
||||
CreateListOfCapturedClips(clickTime);
|
||||
|
||||
} else {
|
||||
mCapturedClip = NULL;
|
||||
mCapturedClipArray.clear();
|
||||
mCapturedTrack = vt;
|
||||
}
|
||||
|
||||
mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive;
|
||||
|
||||
mCapturedTrack = vt;
|
||||
mCapturedRect = rect;
|
||||
|
||||
mMouseClickX = event.m_x;
|
||||
@ -3587,6 +3519,83 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
|
||||
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
|
||||
// duplication of this logic)
|
||||
void TrackPanel::AddClipsToCaptured(Track *t, bool withinSelection)
|
||||
@ -3877,6 +3886,24 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
|
||||
|
||||
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
|
||||
if (mCapturedClipArray.size())
|
||||
#else
|
||||
@ -3947,18 +3974,55 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
|
||||
if (link)
|
||||
link->Offset(mHSlideAmount);
|
||||
}
|
||||
}
|
||||
|
||||
if (mCapturedClipIsSelection) {
|
||||
// Slide the selection, too
|
||||
mViewInfo->selectedRegion.move(mHSlideAmount);
|
||||
void TrackPanel::OnClipMove(bool right)
|
||||
{
|
||||
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);
|
||||
|
||||
if (!stereo){
|
||||
if (stereo){
|
||||
mPopupMenuTarget->SetPanFromChannelType();
|
||||
mPopupMenuTarget->SetChannel(Track::MonoChannel);
|
||||
}
|
||||
mPopupMenuTarget->SetChannel(Track::MonoChannel);
|
||||
|
||||
|
||||
// Assume partner is present, and is wave
|
||||
auto partner = static_cast<WaveTrack*>(mPopupMenuTarget->GetLink());
|
||||
@ -8086,10 +8151,11 @@ void TrackPanel::SplitStereo(bool stereo)
|
||||
if (partner)
|
||||
{
|
||||
partner->SetName(mPopupMenuTarget->GetName());
|
||||
if (!stereo){
|
||||
if (stereo){
|
||||
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.
|
||||
if (ODManager::IsInstanceCreated() && partner->GetKind() == Track::Wave)
|
||||
|
@ -252,6 +252,8 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
||||
// (ignoring any fisheye)
|
||||
virtual double GetScreenEndTime() const;
|
||||
|
||||
virtual void OnClipMove(bool right);
|
||||
|
||||
protected:
|
||||
virtual MixerBoard* GetMixerBoard();
|
||||
/** @brief Populates the track pop-down menu with the common set of
|
||||
@ -377,6 +379,8 @@ protected:
|
||||
virtual void HandleSlide(wxMouseEvent & event);
|
||||
virtual void StartSlide(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, double t0, double t1);
|
||||
|
||||
|
@ -2228,6 +2228,17 @@ WaveClip* WaveTrack::GetClipAtSample(sampleCount sample)
|
||||
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)
|
||||
{
|
||||
WaveClip* clip = GetClipAtX(xcoord);
|
||||
|
@ -276,6 +276,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack {
|
||||
Envelope* GetEnvelopeAtX(int xcoord);
|
||||
|
||||
WaveClip* GetClipAtSample(sampleCount sample);
|
||||
WaveClip* GetClipAtTime(double time);
|
||||
|
||||
//
|
||||
// Getting information about the track's internal block sizes
|
||||
|
@ -164,7 +164,11 @@ void GUIPrefs::PopulateOrExchange(ShuttleGui & S)
|
||||
|
||||
S.StartStatic(_("Theme"));
|
||||
{
|
||||
#ifdef EXPERIMENTAL_DA
|
||||
S.StartRadioButtonGroup(wxT("/GUI/Theme"), wxT("dark"));
|
||||
#else
|
||||
S.StartRadioButtonGroup(wxT("/GUI/Theme"), wxT("classic"));
|
||||
#endif
|
||||
{
|
||||
S.TieRadioButton(_("Classic"),
|
||||
wxT("classic"));
|
||||
|
Loading…
x
Reference in New Issue
Block a user