mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-01 08:29:27 +02:00
Move code for Wave track menu items
This commit is contained in:
parent
ba5f6ce411
commit
a313bcdb11
@ -173,7 +173,6 @@ is time to refresh some aspect of the screen.
|
||||
#include "NumberScale.h"
|
||||
#include "Prefs.h"
|
||||
#include "RefreshCode.h"
|
||||
#include "ShuttleGui.h"
|
||||
#include "TrackArtist.h"
|
||||
#include "TrackPanelAx.h"
|
||||
#include "UndoManager.h"
|
||||
@ -185,10 +184,8 @@ is time to refresh some aspect of the screen.
|
||||
|
||||
#include "ondemand/ODManager.h"
|
||||
|
||||
#include "prefs/PrefsDialog.h"
|
||||
#include "prefs/SpectrumPrefs.h"
|
||||
#include "prefs/TracksBehaviorsPrefs.h"
|
||||
#include "prefs/WaveformPrefs.h"
|
||||
#include "prefs/SpectrogramSettings.h"
|
||||
#include "prefs/WaveformSettings.h"
|
||||
|
||||
#include "toolbars/ControlToolBar.h"
|
||||
#include "toolbars/ToolsToolBar.h"
|
||||
@ -286,38 +283,6 @@ template < class CLIPPEE, class CLIPVAL >
|
||||
enum {
|
||||
TrackPanelFirstID = 2000,
|
||||
|
||||
OnChannelLeftID,
|
||||
OnChannelRightID,
|
||||
OnChannelMonoID,
|
||||
|
||||
OnRate8ID, // <---
|
||||
OnRate11ID, // |
|
||||
OnRate16ID, // |
|
||||
OnRate22ID, // |
|
||||
OnRate44ID, // |
|
||||
OnRate48ID, // | Leave these in order
|
||||
OnRate88ID, // |
|
||||
OnRate96ID, // |
|
||||
OnRate176ID, // | see OnTrackMenu()
|
||||
OnRate192ID, // |
|
||||
OnRate352ID, // |
|
||||
OnRate384ID, // |
|
||||
OnRateOtherID, // |
|
||||
// |
|
||||
On16BitID, // |
|
||||
On24BitID, // |
|
||||
OnFloatID, // <---
|
||||
|
||||
OnWaveformID,
|
||||
OnWaveformDBID,
|
||||
OnSpectrumID,
|
||||
OnSpectrogramSettingsID,
|
||||
|
||||
OnSplitStereoID,
|
||||
OnSplitStereoMonoID,
|
||||
OnMergeStereoID,
|
||||
OnSwapChannelsID,
|
||||
|
||||
// Reserve an ample block of ids for waveform scale types
|
||||
OnFirstWaveformScaleID,
|
||||
OnLastWaveformScaleID = OnFirstWaveformScaleID + 9,
|
||||
@ -343,18 +308,6 @@ BEGIN_EVENT_TABLE(TrackPanel, OverlayPanel)
|
||||
EVT_KILL_FOCUS(TrackPanel::OnKillFocus)
|
||||
EVT_CONTEXT_MENU(TrackPanel::OnContextMenu)
|
||||
|
||||
EVT_MENU_RANGE(OnChannelLeftID, OnChannelMonoID,
|
||||
TrackPanel::OnChannelChange)
|
||||
EVT_MENU_RANGE(OnWaveformID, OnSpectrumID, TrackPanel::OnSetDisplay)
|
||||
EVT_MENU(OnSpectrogramSettingsID, TrackPanel::OnSpectrogramSettings)
|
||||
EVT_MENU_RANGE(OnRate8ID, OnRate384ID, TrackPanel::OnRateChange)
|
||||
EVT_MENU_RANGE(On16BitID, OnFloatID, TrackPanel::OnFormatChange)
|
||||
EVT_MENU(OnRateOtherID, TrackPanel::OnRateOther)
|
||||
EVT_MENU(OnSwapChannelsID, TrackPanel::OnSwapChannels)
|
||||
EVT_MENU(OnSplitStereoID, TrackPanel::OnSplitStereo)
|
||||
EVT_MENU(OnSplitStereoMonoID, TrackPanel::OnSplitStereoMono)
|
||||
EVT_MENU(OnMergeStereoID, TrackPanel::OnMergeStereo)
|
||||
|
||||
EVT_MENU_RANGE(OnFirstWaveformScaleID, OnLastWaveformScaleID, TrackPanel::OnWaveformScaleType)
|
||||
EVT_MENU_RANGE(OnFirstSpectrumScaleID, OnLastSpectrumScaleID, TrackPanel::OnSpectrumScaleType)
|
||||
|
||||
@ -461,12 +414,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
|
||||
mAdjustLeftSelectionCursor = std::make_unique<wxCursor>(wxCURSOR_POINT_LEFT);
|
||||
mAdjustRightSelectionCursor = std::make_unique<wxCursor>(wxCURSOR_POINT_RIGHT);
|
||||
|
||||
// Menu pointers are set to NULL here. Delay building of menus until after
|
||||
// the command managter is finished, so that we can look up shortcut
|
||||
// key strings that need to appear in some of the popup menus.
|
||||
mWaveTrackMenu = NULL;
|
||||
mChannelItemsInsertionPoint = 0;
|
||||
|
||||
mTrackArtist = std::make_unique<TrackArtist>();
|
||||
|
||||
mTrackArtist->SetMargins(1, kTopMargin, kRightMargin, kBottomMargin);
|
||||
@ -559,67 +506,11 @@ SelectionState &TrackPanel::GetSelectionState()
|
||||
return GetProject()->GetSelectionState();
|
||||
}
|
||||
|
||||
void TrackPanel::BuildMenusIfNeeded(void)
|
||||
{
|
||||
if (!mRateMenu)
|
||||
BuildMenus();
|
||||
}
|
||||
|
||||
void TrackPanel::BuildMenus(void)
|
||||
{
|
||||
// Get rid of existing menus
|
||||
DeleteMenus();
|
||||
|
||||
// Use AppendCheckItem so we can have ticks beside the items.
|
||||
// We would use AppendRadioItem but it only currently works on windows and GTK.
|
||||
auto rateMenu = std::make_unique<wxMenu>();
|
||||
rateMenu->AppendRadioItem(OnRate8ID, wxT("8000 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRate11ID, wxT("11025 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRate16ID, wxT("16000 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRate22ID, wxT("22050 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRate44ID, wxT("44100 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRate48ID, wxT("48000 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRate88ID, wxT("88200 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRate96ID, wxT("96000 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRate176ID, wxT("176400 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRate192ID, wxT("192000 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRate352ID, wxT("352800 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRate384ID, wxT("384000 Hz"));
|
||||
rateMenu->AppendRadioItem(OnRateOtherID, _("&Other..."));
|
||||
|
||||
auto formatMenu = std::make_unique<wxMenu>();
|
||||
formatMenu->AppendRadioItem(On16BitID, GetSampleFormatStr(int16Sample));
|
||||
formatMenu->AppendRadioItem(On24BitID, GetSampleFormatStr(int24Sample));
|
||||
formatMenu->AppendRadioItem(OnFloatID, GetSampleFormatStr(floatSample));
|
||||
|
||||
/* build the pop-down menu used on wave (sampled audio) tracks */
|
||||
mWaveTrackMenu = std::make_unique<wxMenu>();
|
||||
mWaveTrackMenu->AppendRadioItem(OnWaveformID, _("Wa&veform"));
|
||||
mWaveTrackMenu->AppendRadioItem(OnWaveformDBID, _("&Waveform (dB)"));
|
||||
mWaveTrackMenu->AppendRadioItem(OnSpectrumID, _("&Spectrogram"));
|
||||
mWaveTrackMenu->Append(OnSpectrogramSettingsID, _("S&pectrogram Settings..."));
|
||||
mWaveTrackMenu->AppendSeparator();
|
||||
|
||||
// include both mono and stereo items as a work around for bug 1250
|
||||
|
||||
// mWaveTrackMenu->AppendRadioItem(OnChannelMonoID, _("&Mono"));
|
||||
// mWaveTrackMenu->AppendRadioItem(OnChannelLeftID, _("&Left Channel"));
|
||||
// mWaveTrackMenu->AppendRadioItem(OnChannelRightID, _("&Right Channel"));
|
||||
mWaveTrackMenu->Append(OnMergeStereoID, _("Ma&ke Stereo Track"));
|
||||
mWaveTrackMenu->Append(OnSwapChannelsID, _("Swap Stereo &Channels"));
|
||||
mWaveTrackMenu->Append(OnSplitStereoID, _("Spl&it Stereo Track"));
|
||||
// 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()));
|
||||
|
||||
mWaveTrackMenu->AppendSeparator();
|
||||
|
||||
mWaveTrackMenu->Append(0, _("Rat&e"), (mRateMenu = rateMenu.release()));
|
||||
|
||||
/*
|
||||
mRulerWaveformMenu = std::make_unique<wxMenu>();
|
||||
BuildVRulerMenuItems
|
||||
@ -651,12 +542,6 @@ void TrackPanel::BuildVRulerMenuItems
|
||||
|
||||
void TrackPanel::DeleteMenus(void)
|
||||
{
|
||||
// Note that the submenus (mRateMenu, ...)
|
||||
// are deleted by their parent
|
||||
|
||||
mRateMenu = mFormatMenu = nullptr;
|
||||
|
||||
mWaveTrackMenu.reset();
|
||||
mRulerWaveformMenu.reset();
|
||||
mRulerSpectrumMenu.reset();
|
||||
}
|
||||
@ -5885,8 +5770,6 @@ void TrackPanel::ScrollIntoView(int x)
|
||||
|
||||
void TrackPanel::OnTrackMenu(Track *t)
|
||||
{
|
||||
BuildMenusIfNeeded();
|
||||
|
||||
if(!t) {
|
||||
t = GetFocusedTrack();
|
||||
if(!t)
|
||||
@ -5904,74 +5787,8 @@ void TrackPanel::OnTrackMenu(Track *t)
|
||||
|
||||
mPopupMenuTarget = t;
|
||||
|
||||
Track *next = mTracks->GetNext(t);
|
||||
|
||||
wxMenu *theMenu = NULL;
|
||||
|
||||
if (t->GetKind() == Track::Wave) {
|
||||
theMenu = mWaveTrackMenu.get();
|
||||
const bool isMono = !t->GetLinked();
|
||||
const bool canMakeStereo =
|
||||
(next && isMono && !next->GetLinked() &&
|
||||
next->GetKind() == Track::Wave);
|
||||
|
||||
// Unsafe to change channels during real-time preview (bug 1560)
|
||||
bool unsafe = EffectManager::Get().RealtimeIsActive() && IsUnsafe();
|
||||
theMenu->Enable(OnSwapChannelsID, t->GetLinked() && !unsafe);
|
||||
theMenu->Enable(OnMergeStereoID, canMakeStereo && !unsafe);
|
||||
theMenu->Enable(OnSplitStereoID, t->GetLinked() && !unsafe);
|
||||
|
||||
// Several menu items no longer needed....
|
||||
#if 0
|
||||
theMenu->Enable(OnSplitStereoMonoID, t->GetLinked() && !unsafe);
|
||||
|
||||
// We only need to set check marks. Clearing checks causes problems on Linux (bug 851)
|
||||
// + Setting unchecked items to false is to get round a linux bug
|
||||
switch (t->GetChannel()) {
|
||||
case Track::LeftChannel:
|
||||
theMenu->Check(OnChannelLeftID, true);
|
||||
theMenu->Check(OnChannelRightID, false);
|
||||
theMenu->Check(OnChannelMonoID, false);
|
||||
break;
|
||||
case Track::RightChannel:
|
||||
theMenu->Check(OnChannelRightID, true);
|
||||
theMenu->Check(OnChannelLeftID, false);
|
||||
theMenu->Check(OnChannelMonoID, false);
|
||||
break;
|
||||
default:
|
||||
theMenu->Check(OnChannelMonoID, true);
|
||||
theMenu->Check(OnChannelLeftID, false);
|
||||
theMenu->Check(OnChannelRightID, false);
|
||||
}
|
||||
|
||||
theMenu->Enable(OnChannelMonoID, !t->GetLinked());
|
||||
theMenu->Enable(OnChannelLeftID, !t->GetLinked());
|
||||
theMenu->Enable(OnChannelRightID, !t->GetLinked());
|
||||
#endif
|
||||
|
||||
WaveTrack *const track = (WaveTrack *)t;
|
||||
const int display = track->GetDisplay();
|
||||
theMenu->Check(
|
||||
(display == WaveTrack::Waveform)
|
||||
? (track->GetWaveformSettings().isLinear() ? OnWaveformID : OnWaveformDBID)
|
||||
: OnSpectrumID,
|
||||
true
|
||||
);
|
||||
// Bug 1253. Shouldn't open preferences if audio is busy.
|
||||
// We can't change them on the fly yet anyway.
|
||||
const bool bAudioBusy = gAudioIO->IsBusy();
|
||||
theMenu->Enable(OnSpectrogramSettingsID,
|
||||
(display == WaveTrack::Spectrum) && !bAudioBusy);
|
||||
|
||||
SetMenuCheck(*mRateMenu, IdOfRate((int) track->GetRate()));
|
||||
SetMenuCheck(*mFormatMenu, IdOfFormat(track->GetSampleFormat()));
|
||||
|
||||
unsafe = IsUnsafe();
|
||||
for (int i = OnRate8ID; i <= OnFloatID; i++) {
|
||||
theMenu->Enable(i, !unsafe);
|
||||
}
|
||||
}
|
||||
|
||||
if (theMenu) {
|
||||
//We need to find the location of the menu rectangle.
|
||||
const wxRect rect = FindTrackRect(t,true);
|
||||
@ -6177,521 +5994,6 @@ void TrackPanel::DrawShadow(Track * /* t */ , wxDC * dc, const wxRect & rect)
|
||||
AColor::Line(*dc, right, rect.y, right, rect.y + 1);
|
||||
}
|
||||
|
||||
/// Handle the menu options that change a track between
|
||||
/// left channel, right channel, and mono.
|
||||
static int channels[] = { Track::LeftChannel, Track::RightChannel,
|
||||
Track::MonoChannel
|
||||
};
|
||||
|
||||
static const wxChar *channelmsgs[] = { _("Left Channel"), _("Right Channel"),
|
||||
_("Mono")
|
||||
};
|
||||
|
||||
void TrackPanel::OnChannelChange(wxCommandEvent & event)
|
||||
{
|
||||
int id = event.GetId();
|
||||
wxASSERT(id >= OnChannelLeftID && id <= OnChannelMonoID);
|
||||
wxASSERT(mPopupMenuTarget);
|
||||
mPopupMenuTarget->SetChannel(channels[id - OnChannelLeftID]);
|
||||
MakeParentPushState(wxString::Format(_("Changed '%s' to %s"),
|
||||
mPopupMenuTarget->GetName().c_str(),
|
||||
channelmsgs[id - OnChannelLeftID]),
|
||||
_("Channel"));
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
/// Swap the left and right channels of a stero track...
|
||||
void TrackPanel::OnSwapChannels(wxCommandEvent & WXUNUSED(event))
|
||||
{
|
||||
Track *partner = mPopupMenuTarget->GetLink();
|
||||
Track *const focused = GetFocusedTrack();
|
||||
const bool hasFocus =
|
||||
(focused == mPopupMenuTarget || focused == partner);
|
||||
|
||||
SplitStereo(false);
|
||||
mPopupMenuTarget->SetChannel(Track::RightChannel);
|
||||
partner->SetChannel(Track::LeftChannel);
|
||||
|
||||
(mTracks->MoveUp(partner));
|
||||
partner->SetLinked(true);
|
||||
|
||||
MixerBoard* pMixerBoard = this->GetMixerBoard();
|
||||
if (pMixerBoard) {
|
||||
pMixerBoard->UpdateTrackClusters();
|
||||
}
|
||||
|
||||
if (hasFocus)
|
||||
SetFocusedTrack(partner);
|
||||
|
||||
MakeParentPushState(wxString::Format(_("Swapped Channels in '%s'"),
|
||||
mPopupMenuTarget->GetName().c_str()),
|
||||
_("Swap Channels"));
|
||||
|
||||
}
|
||||
|
||||
/// Split a stereo track into two tracks...
|
||||
void TrackPanel::OnSplitStereo(wxCommandEvent & WXUNUSED(event))
|
||||
{
|
||||
SplitStereo(true);
|
||||
MakeParentPushState(wxString::Format(_("Split stereo track '%s'"),
|
||||
mPopupMenuTarget->GetName().c_str()),
|
||||
_("Split"));
|
||||
}
|
||||
|
||||
/// Split a stereo track into two mono tracks...
|
||||
void TrackPanel::OnSplitStereoMono(wxCommandEvent & WXUNUSED(event))
|
||||
{
|
||||
SplitStereo(false);
|
||||
MakeParentPushState(wxString::Format(_("Split Stereo to Mono '%s'"),
|
||||
mPopupMenuTarget->GetName().c_str()),
|
||||
_("Split to Mono"));
|
||||
}
|
||||
|
||||
/// Split a stereo track into two tracks...
|
||||
void TrackPanel::SplitStereo(bool stereo)
|
||||
{
|
||||
wxASSERT(mPopupMenuTarget);
|
||||
|
||||
if (stereo){
|
||||
mPopupMenuTarget->SetPanFromChannelType();
|
||||
}
|
||||
mPopupMenuTarget->SetChannel(Track::MonoChannel);
|
||||
|
||||
|
||||
// Assume partner is present, and is wave
|
||||
auto partner = static_cast<WaveTrack*>(mPopupMenuTarget->GetLink());
|
||||
wxASSERT(partner);
|
||||
if (!partner)
|
||||
return;
|
||||
|
||||
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
||||
if(!stereo && MONO_WAVE_PAN(mPopupMenuTarget))
|
||||
// Come here only from wave track menu
|
||||
static_cast<WaveTrack*>(mPopupMenuTarget)->SetVirtualState(true,true);
|
||||
if(!stereo && MONO_WAVE_PAN(partner))
|
||||
partner->SetVirtualState(true,true);
|
||||
#endif
|
||||
|
||||
if (partner)
|
||||
{
|
||||
partner->SetName(mPopupMenuTarget->GetName());
|
||||
if (stereo){
|
||||
partner->SetPanFromChannelType();
|
||||
}
|
||||
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)
|
||||
ODManager::Instance()->MakeWaveTrackIndependent(partner);
|
||||
}
|
||||
|
||||
mPopupMenuTarget->SetLinked(false);
|
||||
//make sure neither track is smaller than its minimum height
|
||||
if (mPopupMenuTarget->GetHeight() < mPopupMenuTarget->GetMinimizedHeight())
|
||||
mPopupMenuTarget->SetHeight(mPopupMenuTarget->GetMinimizedHeight());
|
||||
if (partner)
|
||||
{
|
||||
if (partner->GetHeight() < partner->GetMinimizedHeight())
|
||||
partner->SetHeight(partner->GetMinimizedHeight());
|
||||
|
||||
// Make tracks the same height
|
||||
if (mPopupMenuTarget->GetHeight() != partner->GetHeight())
|
||||
{
|
||||
mPopupMenuTarget->SetHeight(((mPopupMenuTarget->GetHeight())+(partner->GetHeight())) / 2.0);
|
||||
partner->SetHeight(mPopupMenuTarget->GetHeight());
|
||||
}
|
||||
}
|
||||
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
/// Merge two tracks into one stereo track ??
|
||||
void TrackPanel::OnMergeStereo(wxCommandEvent & WXUNUSED(event))
|
||||
{
|
||||
wxASSERT(mPopupMenuTarget);
|
||||
mPopupMenuTarget->SetLinked(true);
|
||||
Track *partner = mPopupMenuTarget->GetLink();
|
||||
|
||||
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
||||
if(MONO_WAVE_PAN(mPopupMenuTarget))
|
||||
((WaveTrack*)mPopupMenuTarget)->SetVirtualState(false);
|
||||
if(MONO_WAVE_PAN(partner))
|
||||
((WaveTrack*)partner)->SetVirtualState(false);
|
||||
#endif
|
||||
|
||||
if (partner) {
|
||||
// Set partner's parameters to match target.
|
||||
partner->Merge(*mPopupMenuTarget);
|
||||
|
||||
mPopupMenuTarget->SetPan( 0.0f );
|
||||
mPopupMenuTarget->SetChannel(Track::LeftChannel);
|
||||
partner->SetPan( 0.0f );
|
||||
partner->SetChannel(Track::RightChannel);
|
||||
|
||||
// Set NEW track heights and minimized state
|
||||
bool bBothMinimizedp=((mPopupMenuTarget->GetMinimized())&&(partner->GetMinimized()));
|
||||
mPopupMenuTarget->SetMinimized(false);
|
||||
partner->SetMinimized(false);
|
||||
int AverageHeight=(mPopupMenuTarget->GetHeight() + partner->GetHeight())/ 2;
|
||||
mPopupMenuTarget->SetHeight(AverageHeight);
|
||||
partner->SetHeight(AverageHeight);
|
||||
mPopupMenuTarget->SetMinimized(bBothMinimizedp);
|
||||
partner->SetMinimized(bBothMinimizedp);
|
||||
|
||||
//On Demand - join the queues together.
|
||||
WaveTrack *wt, *pwt;
|
||||
if(ODManager::IsInstanceCreated() &&
|
||||
// Assume linked track is wave or null
|
||||
nullptr != (pwt = static_cast<WaveTrack*>(partner)) &&
|
||||
// Come here only from the wave track menu
|
||||
nullptr != (wt = static_cast<WaveTrack*>(mPopupMenuTarget)))
|
||||
if(!ODManager::Instance()->MakeWaveTrackDependent(pwt, wt))
|
||||
{
|
||||
;
|
||||
//TODO: in the future, we will have to check the return value of MakeWaveTrackDependent -
|
||||
//if the tracks cannot merge, it returns false, and in that case we should not allow a merging.
|
||||
//for example it returns false when there are two different types of ODTasks on each track's queue.
|
||||
//we will need to display this to the user.
|
||||
}
|
||||
|
||||
MakeParentPushState(wxString::Format(_("Made '%s' a stereo track"),
|
||||
mPopupMenuTarget->GetName().
|
||||
c_str()),
|
||||
_("Make Stereo"));
|
||||
} else
|
||||
mPopupMenuTarget->SetLinked(false);
|
||||
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
class ViewSettingsDialog final : public PrefsDialog
|
||||
{
|
||||
public:
|
||||
ViewSettingsDialog
|
||||
(wxWindow *parent, const wxString &title, PrefsDialog::Factories &factories,
|
||||
int page)
|
||||
: PrefsDialog(parent, title, factories)
|
||||
, mPage(page)
|
||||
{
|
||||
}
|
||||
|
||||
long GetPreferredPage() override
|
||||
{
|
||||
return mPage;
|
||||
}
|
||||
|
||||
void SavePreferredPage() override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const int mPage;
|
||||
};
|
||||
|
||||
void TrackPanel::OnSpectrogramSettings(wxCommandEvent &)
|
||||
{
|
||||
|
||||
if (gAudioIO->IsBusy()){
|
||||
wxMessageBox(_("To change Spectrogram Settings, stop any\n."
|
||||
"playing or recording first."),
|
||||
_("Stop the Audio First"), wxOK | wxICON_EXCLAMATION | wxCENTRE);
|
||||
return;
|
||||
}
|
||||
// Get here only from the wave track menu
|
||||
const auto wt = static_cast<WaveTrack*>(mPopupMenuTarget);
|
||||
// WaveformPrefsFactory waveformFactory(wt);
|
||||
//TracksBehaviorsPrefsFactory tracksBehaviorsFactory();
|
||||
SpectrumPrefsFactory spectrumFactory(wt);
|
||||
|
||||
PrefsDialog::Factories factories;
|
||||
// factories.push_back(&waveformFactory);
|
||||
factories.push_back(&spectrumFactory);
|
||||
const int page = (wt->GetDisplay() == WaveTrack::Spectrum)
|
||||
? 1 : 0;
|
||||
|
||||
wxString title(wt->GetName() + wxT(": "));
|
||||
ViewSettingsDialog dialog(this, title, factories, page);
|
||||
|
||||
if (0 != dialog.ShowModal()) {
|
||||
MakeParentModifyState(true);
|
||||
// Redraw
|
||||
Refresh(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the Display mode based on the menu choice in the Track Menu.
|
||||
/// Note that gModes MUST BE IN THE SAME ORDER AS THE MENU CHOICES!!
|
||||
/// const wxChar *gModes[] = { wxT("waveform"), wxT("waveformDB"),
|
||||
/// wxT("spectrum"), wxT("pitch") };
|
||||
void TrackPanel::OnSetDisplay(wxCommandEvent & event)
|
||||
{
|
||||
int idInt = event.GetId();
|
||||
wxASSERT(idInt >= OnWaveformID && idInt <= OnSpectrumID);
|
||||
wxASSERT(mPopupMenuTarget
|
||||
&& mPopupMenuTarget->GetKind() == Track::Wave);
|
||||
|
||||
bool linear = false;
|
||||
WaveTrack::WaveTrackDisplay id;
|
||||
switch (idInt) {
|
||||
default:
|
||||
case OnWaveformID:
|
||||
linear = true, id = WaveTrack::Waveform; break;
|
||||
case OnWaveformDBID:
|
||||
id = WaveTrack::Waveform; break;
|
||||
case OnSpectrumID:
|
||||
id = WaveTrack::Spectrum; break;
|
||||
}
|
||||
WaveTrack *wt = (WaveTrack *) mPopupMenuTarget;
|
||||
const bool wrongType = wt->GetDisplay() != id;
|
||||
const bool wrongScale =
|
||||
(id == WaveTrack::Waveform &&
|
||||
wt->GetWaveformSettings().isLinear() != linear);
|
||||
if (wrongType || wrongScale) {
|
||||
wt->SetLastScaleType();
|
||||
wt->SetDisplay(WaveTrack::WaveTrackDisplay(id));
|
||||
if (wrongScale)
|
||||
wt->GetIndependentWaveformSettings().scaleType = linear
|
||||
? WaveformSettings::stLinear
|
||||
: WaveformSettings::stLogarithmic;
|
||||
|
||||
// Assume linked track is wave or null
|
||||
const auto l = static_cast<WaveTrack*>(wt->GetLink());
|
||||
if (l) {
|
||||
l->SetLastScaleType();
|
||||
l->SetDisplay(WaveTrack::WaveTrackDisplay(id));
|
||||
if (wrongScale)
|
||||
l->GetIndependentWaveformSettings().scaleType = linear
|
||||
? WaveformSettings::stLinear
|
||||
: WaveformSettings::stLogarithmic;
|
||||
}
|
||||
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
||||
if (wt->GetDisplay() == WaveTrack::Waveform) {
|
||||
wt->SetVirtualState(false);
|
||||
}else if (id == WaveTrack::Waveform) {
|
||||
wt->SetVirtualState(true);
|
||||
}
|
||||
#endif
|
||||
UpdateVRuler(wt);
|
||||
|
||||
MakeParentModifyState(true);
|
||||
Refresh(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the sample rate for a track, and if it is linked to
|
||||
/// another track, that one as well.
|
||||
void TrackPanel::SetRate(WaveTrack * wt, double rate)
|
||||
{
|
||||
wt->SetRate(rate);
|
||||
// Assume linked track is wave or null
|
||||
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
|
||||
if (partner)
|
||||
partner->SetRate(rate);
|
||||
// Separate conversion of "rate" enables changing the decimals without affecting i18n
|
||||
wxString rateString = wxString::Format(wxT("%.3f"), rate);
|
||||
MakeParentPushState(wxString::Format(_("Changed '%s' to %s Hz"),
|
||||
wt->GetName().c_str(), rateString.c_str()),
|
||||
_("Rate Change"));
|
||||
}
|
||||
|
||||
/// Handles the selection from the Format submenu of the
|
||||
/// track menu.
|
||||
void TrackPanel::OnFormatChange(wxCommandEvent & event)
|
||||
{
|
||||
BuildMenusIfNeeded();
|
||||
|
||||
int id = event.GetId();
|
||||
wxASSERT(id >= On16BitID && id <= OnFloatID);
|
||||
wxASSERT(mPopupMenuTarget
|
||||
&& mPopupMenuTarget->GetKind() == Track::Wave);
|
||||
|
||||
sampleFormat newFormat = int16Sample;
|
||||
|
||||
switch (id) {
|
||||
case On16BitID:
|
||||
newFormat = int16Sample;
|
||||
break;
|
||||
case On24BitID:
|
||||
newFormat = int24Sample;
|
||||
break;
|
||||
case OnFloatID:
|
||||
newFormat = floatSample;
|
||||
break;
|
||||
default:
|
||||
// ERROR -- should not happen
|
||||
wxASSERT(false);
|
||||
break;
|
||||
}
|
||||
if (newFormat == ((WaveTrack*)mPopupMenuTarget)->GetSampleFormat())
|
||||
return; // Nothing to do.
|
||||
|
||||
((WaveTrack*)mPopupMenuTarget)->ConvertToSampleFormat(newFormat);
|
||||
// Assume linked track is wave or null
|
||||
const auto partner =
|
||||
static_cast<WaveTrack*>(mPopupMenuTarget->GetLink());
|
||||
if (partner)
|
||||
partner->ConvertToSampleFormat(newFormat);
|
||||
|
||||
MakeParentPushState(wxString::Format(_("Changed '%s' to %s"),
|
||||
mPopupMenuTarget->GetName().
|
||||
c_str(),
|
||||
GetSampleFormatStr(newFormat)),
|
||||
_("Format Change"));
|
||||
|
||||
SetMenuCheck( *mFormatMenu, id );
|
||||
MakeParentRedrawScrollbars();
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
/// Converts a format enumeration to a wxWidgets menu item Id.
|
||||
int TrackPanel::IdOfFormat( int format )
|
||||
{
|
||||
switch (format) {
|
||||
case int16Sample:
|
||||
return On16BitID;
|
||||
case int24Sample:
|
||||
return On24BitID;
|
||||
case floatSample:
|
||||
return OnFloatID;
|
||||
default:
|
||||
// ERROR -- should not happen
|
||||
wxASSERT( false );
|
||||
break;
|
||||
}
|
||||
return OnFloatID;// Compiler food.
|
||||
}
|
||||
|
||||
/// Puts a check mark at a given position in a menu.
|
||||
void TrackPanel::SetMenuCheck( wxMenu & menu, int newId )
|
||||
{
|
||||
auto & list = menu.GetMenuItems();
|
||||
|
||||
for ( auto item : list )
|
||||
{
|
||||
auto id = item->GetId();
|
||||
// We only need to set check marks. Clearing checks causes problems on Linux (bug 851)
|
||||
if (id==newId)
|
||||
menu.Check( id, true );
|
||||
}
|
||||
}
|
||||
|
||||
const int nRates=12;
|
||||
|
||||
/// gRates MUST CORRESPOND DIRECTLY TO THE RATES AS LISTED IN THE MENU!!
|
||||
/// IN THE SAME ORDER!!
|
||||
static int gRates[nRates] = { 8000, 11025, 16000, 22050, 44100, 48000, 88200, 96000,
|
||||
176400, 192000, 352800, 384000 };
|
||||
|
||||
/// This method handles the selection from the Rate
|
||||
/// submenu of the track menu, except for "Other" (/see OnRateOther).
|
||||
void TrackPanel::OnRateChange(wxCommandEvent & event)
|
||||
{
|
||||
BuildMenusIfNeeded();
|
||||
|
||||
int id = event.GetId();
|
||||
wxASSERT(id >= OnRate8ID && id <= OnRate384ID);
|
||||
|
||||
SetMenuCheck( *mRateMenu, id );
|
||||
// Come here only from wave track menu
|
||||
SetRate(static_cast<WaveTrack*>(mPopupMenuTarget), gRates[id - OnRate8ID]);
|
||||
|
||||
MakeParentRedrawScrollbars();
|
||||
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
/// Converts a sampling rate to a wxWidgets menu item id
|
||||
int TrackPanel::IdOfRate( int rate )
|
||||
{
|
||||
for(int i=0;i<nRates;i++) {
|
||||
if( gRates[i] == rate )
|
||||
return i+OnRate8ID;
|
||||
}
|
||||
return OnRateOtherID;
|
||||
}
|
||||
|
||||
void TrackPanel::OnRateOther(wxCommandEvent &event)
|
||||
{
|
||||
BuildMenusIfNeeded();
|
||||
|
||||
// Come here only from the wave track menu
|
||||
const auto wt = static_cast<WaveTrack*>(mPopupMenuTarget);
|
||||
wxASSERT(wt);
|
||||
|
||||
int newRate;
|
||||
|
||||
/// \todo Remove artificial constants!!
|
||||
/// \todo Make a real dialog box out of this!!
|
||||
while (true)
|
||||
{
|
||||
wxDialogWrapper dlg(this, wxID_ANY, wxString(_("Set Rate")));
|
||||
dlg.SetName(dlg.GetTitle());
|
||||
ShuttleGui S(&dlg, eIsCreating);
|
||||
wxString rate;
|
||||
wxArrayString rates;
|
||||
wxComboBox *cb;
|
||||
|
||||
rate.Printf(wxT("%ld"), lrint(((WaveTrack *) mPopupMenuTarget)->GetRate()));
|
||||
|
||||
rates.Add(wxT("8000"));
|
||||
rates.Add(wxT("11025"));
|
||||
rates.Add(wxT("16000"));
|
||||
rates.Add(wxT("22050"));
|
||||
rates.Add(wxT("44100"));
|
||||
rates.Add(wxT("48000"));
|
||||
rates.Add(wxT("88200"));
|
||||
rates.Add(wxT("96000"));
|
||||
rates.Add(wxT("176400"));
|
||||
rates.Add(wxT("192000"));
|
||||
rates.Add(wxT("352800"));
|
||||
rates.Add(wxT("384000"));
|
||||
|
||||
S.StartVerticalLay(true);
|
||||
{
|
||||
S.SetBorder(10);
|
||||
S.StartHorizontalLay(wxEXPAND, false);
|
||||
{
|
||||
cb = S.AddCombo(_("New sample rate (Hz):"),
|
||||
rate,
|
||||
&rates);
|
||||
#if defined(__WXMAC__)
|
||||
// As of wxMac-2.8.12, setting manually is required
|
||||
// to handle rates not in the list. See: Bug #427
|
||||
cb->SetValue(rate);
|
||||
#endif
|
||||
}
|
||||
S.EndHorizontalLay();
|
||||
S.AddStandardButtons();
|
||||
}
|
||||
S.EndVerticalLay();
|
||||
|
||||
dlg.SetClientSize(dlg.GetSizer()->CalcMin());
|
||||
dlg.Center();
|
||||
|
||||
if (dlg.ShowModal() != wxID_OK)
|
||||
{
|
||||
return; // user cancelled dialog
|
||||
}
|
||||
|
||||
long lrate;
|
||||
if (cb->GetValue().ToLong(&lrate) && lrate >= 1 && lrate <= 1000000)
|
||||
{
|
||||
newRate = (int)lrate;
|
||||
break;
|
||||
}
|
||||
|
||||
wxMessageBox(_("The entered value is invalid"), _("Error"),
|
||||
wxICON_ERROR, this);
|
||||
}
|
||||
|
||||
SetMenuCheck( *mRateMenu, event.GetId() );
|
||||
SetRate(wt, newRate);
|
||||
|
||||
MakeParentRedrawScrollbars();
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
void TrackPanel::OnWaveformScaleType(wxCommandEvent &evt)
|
||||
{
|
||||
// Get here only from vertical ruler menu for wave tracks
|
||||
|
@ -258,7 +258,6 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
||||
|
||||
virtual ~ TrackPanel();
|
||||
|
||||
virtual void BuildMenusIfNeeded(void);
|
||||
virtual void BuildMenus(void);
|
||||
|
||||
virtual void DeleteMenus(void);
|
||||
@ -489,10 +488,6 @@ protected:
|
||||
virtual void MakeParentModifyState(bool bWantsAutoSave); // if true, writes auto-save file. Should set only if you really want the state change restored after
|
||||
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
||||
|
||||
virtual void OnChannelChange(wxCommandEvent &event);
|
||||
virtual void OnSpectrogramSettings(wxCommandEvent &event);
|
||||
virtual void OnSetDisplay (wxCommandEvent &event);
|
||||
|
||||
virtual void OnWaveformScaleType(wxCommandEvent &event);
|
||||
virtual void OnSpectrumScaleType(wxCommandEvent &event);
|
||||
|
||||
@ -500,19 +495,6 @@ protected:
|
||||
virtual void OnZoomOutVertical(wxCommandEvent &event);
|
||||
virtual void OnZoomFitVertical(wxCommandEvent &event);
|
||||
|
||||
virtual void SetMenuCheck( wxMenu & menu, int newId );
|
||||
virtual void SetRate(WaveTrack *pTrack, double rate);
|
||||
virtual void OnRateChange(wxCommandEvent &event);
|
||||
virtual void OnRateOther(wxCommandEvent &event);
|
||||
|
||||
virtual void OnFormatChange(wxCommandEvent &event);
|
||||
|
||||
virtual void OnSwapChannels(wxCommandEvent &event);
|
||||
virtual void OnSplitStereo(wxCommandEvent &event);
|
||||
virtual void OnSplitStereoMono(wxCommandEvent &event);
|
||||
virtual void SplitStereo(bool stereo);
|
||||
virtual void OnMergeStereo(wxCommandEvent &event);
|
||||
|
||||
// Find track info by coordinate
|
||||
enum class CellType { Label, Track, VRuler, Background };
|
||||
struct FoundCell {
|
||||
@ -570,10 +552,6 @@ public:
|
||||
virtual void SetBackgroundCell
|
||||
(const std::shared_ptr< TrackPanelCell > &pCell);
|
||||
|
||||
protected:
|
||||
virtual int IdOfRate( int rate );
|
||||
virtual int IdOfFormat( int format );
|
||||
|
||||
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
||||
void UpdateVirtualStereoOrder();
|
||||
#endif
|
||||
@ -789,16 +767,9 @@ protected:
|
||||
mStretchCursor, mStretchLeftCursor, mStretchRightCursor;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<wxMenu> mWaveTrackMenu;
|
||||
size_t mChannelItemsInsertionPoint {};
|
||||
|
||||
std::unique_ptr<wxMenu>
|
||||
mRulerWaveformMenu, mRulerSpectrumMenu;
|
||||
|
||||
// These sub-menus are owned by parent menus,
|
||||
// so not unique_ptrs
|
||||
wxMenu *mRateMenu{}, *mFormatMenu{};
|
||||
|
||||
Track *mPopupMenuTarget {};
|
||||
|
||||
friend class TrackPanelAx;
|
||||
|
@ -9,15 +9,44 @@ Paul Licameli split from TrackPanel.cpp
|
||||
**********************************************************************/
|
||||
|
||||
#include "../../../../Audacity.h"
|
||||
#include "../../../../Experimental.h"
|
||||
#include "WaveTrackControls.h"
|
||||
#include "../../ui/PlayableTrackButtonHandles.h"
|
||||
#include "WaveTrackSliderHandles.h"
|
||||
|
||||
#include "../../../../AudioIO.h"
|
||||
#include "../../../../HitTestResult.h"
|
||||
#include "../../../../MixerBoard.h"
|
||||
#include "../../../../Project.h"
|
||||
#include "../../../../RefreshCode.h"
|
||||
#include "../../../../WaveTrack.h"
|
||||
#include "../../../../ShuttleGui.h"
|
||||
#include "../../../../TrackPanel.h"
|
||||
#include "../../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../../widgets/PopupMenuTable.h"
|
||||
#include "../../../../ondemand/ODManager.h"
|
||||
#include "../../../../prefs/PrefsDialog.h"
|
||||
#include "../../../../prefs/SpectrumPrefs.h"
|
||||
#include "../../../../prefs/TracksBehaviorsPrefs.h"
|
||||
#include "../../../../prefs/WaveformPrefs.h"
|
||||
|
||||
#include <wx/combobox.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
/// Puts a check mark at a given position in a menu.
|
||||
template<typename Pred>
|
||||
void SetMenuChecks(wxMenu & menu, const Pred &pred)
|
||||
{
|
||||
for (auto &item : menu.GetMenuItems())
|
||||
{
|
||||
if (item->IsCheckable()) {
|
||||
auto id = item->GetId();
|
||||
menu.Check(id, pred(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WaveTrackControls::WaveTrackControls()
|
||||
{
|
||||
@ -67,25 +96,387 @@ HitTestResult WaveTrackControls::HitTest
|
||||
return TrackControls::HitTest(evt, pProject);
|
||||
}
|
||||
|
||||
enum {
|
||||
OnRate8ID = 2001, // <---
|
||||
OnRate11ID, // |
|
||||
OnRate16ID, // |
|
||||
OnRate22ID, // |
|
||||
OnRate44ID, // |
|
||||
OnRate48ID, // | Leave these in order
|
||||
OnRate88ID, // |
|
||||
OnRate96ID, // |
|
||||
OnRate176ID, // |
|
||||
OnRate192ID, // |
|
||||
OnRate352ID, // |
|
||||
OnRate384ID, // |
|
||||
OnRateOtherID, // |
|
||||
// |
|
||||
On16BitID, // |
|
||||
On24BitID, // |
|
||||
OnFloatID, // <---
|
||||
|
||||
OnWaveformID,
|
||||
OnWaveformDBID,
|
||||
OnSpectrumID,
|
||||
OnSpectrogramSettingsID,
|
||||
|
||||
OnChannelLeftID,
|
||||
OnChannelRightID,
|
||||
OnChannelMonoID,
|
||||
|
||||
OnMergeStereoID,
|
||||
|
||||
OnSwapChannelsID,
|
||||
OnSplitStereoID,
|
||||
OnSplitStereoMonoID,
|
||||
|
||||
ChannelMenuID,
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Table class for a sub-menu
|
||||
class FormatMenuTable : public PopupMenuTable
|
||||
{
|
||||
FormatMenuTable() : mpData(NULL) {}
|
||||
DECLARE_POPUP_MENU(FormatMenuTable);
|
||||
|
||||
public:
|
||||
static FormatMenuTable &Instance();
|
||||
|
||||
private:
|
||||
void InitMenu(Menu *pMenu, void *pUserData) override;
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
mpData = NULL;
|
||||
}
|
||||
|
||||
TrackControls::InitMenuData *mpData;
|
||||
|
||||
int IdOfFormat(int format);
|
||||
|
||||
void OnFormatChange(wxCommandEvent & event);
|
||||
};
|
||||
|
||||
FormatMenuTable &FormatMenuTable::Instance()
|
||||
{
|
||||
static FormatMenuTable instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void FormatMenuTable::InitMenu(Menu *pMenu, void *pUserData)
|
||||
{
|
||||
mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
auto formatId = IdOfFormat(pTrack->GetSampleFormat());
|
||||
SetMenuChecks(*pMenu, [=](int id){ return id == formatId; });
|
||||
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
bool unsafe = project->IsAudioActive();
|
||||
for (int i = On16BitID; i <= OnFloatID; i++) {
|
||||
pMenu->Enable(i, !unsafe);
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(FormatMenuTable)
|
||||
POPUP_MENU_RADIO_ITEM(On16BitID,
|
||||
GetSampleFormatStr(int16Sample), OnFormatChange)
|
||||
POPUP_MENU_RADIO_ITEM(On24BitID,
|
||||
GetSampleFormatStr(int24Sample), OnFormatChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnFloatID,
|
||||
GetSampleFormatStr(floatSample), OnFormatChange)
|
||||
END_POPUP_MENU()
|
||||
|
||||
/// Converts a format enumeration to a wxWidgets menu item Id.
|
||||
int FormatMenuTable::IdOfFormat(int format)
|
||||
{
|
||||
switch (format) {
|
||||
case int16Sample:
|
||||
return On16BitID;
|
||||
case int24Sample:
|
||||
return On24BitID;
|
||||
case floatSample:
|
||||
return OnFloatID;
|
||||
default:
|
||||
// ERROR -- should not happen
|
||||
wxASSERT(false);
|
||||
break;
|
||||
}
|
||||
return OnFloatID;// Compiler food.
|
||||
}
|
||||
|
||||
/// Handles the selection from the Format submenu of the
|
||||
/// track menu.
|
||||
void FormatMenuTable::OnFormatChange(wxCommandEvent & event)
|
||||
{
|
||||
int id = event.GetId();
|
||||
wxASSERT(id >= On16BitID && id <= OnFloatID);
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
wxASSERT(pTrack && pTrack->GetKind() == Track::Wave);
|
||||
|
||||
sampleFormat newFormat = int16Sample;
|
||||
|
||||
switch (id) {
|
||||
case On16BitID:
|
||||
newFormat = int16Sample;
|
||||
break;
|
||||
case On24BitID:
|
||||
newFormat = int24Sample;
|
||||
break;
|
||||
case OnFloatID:
|
||||
newFormat = floatSample;
|
||||
break;
|
||||
default:
|
||||
// ERROR -- should not happen
|
||||
wxASSERT(false);
|
||||
break;
|
||||
}
|
||||
if (newFormat == pTrack->GetSampleFormat())
|
||||
return; // Nothing to do.
|
||||
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
TrackList *const tracks = project->GetTracks();
|
||||
|
||||
pTrack->ConvertToSampleFormat(newFormat);
|
||||
|
||||
// Assume partner is wave or null
|
||||
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
|
||||
if (partner)
|
||||
partner->ConvertToSampleFormat(newFormat);
|
||||
|
||||
project->PushState(wxString::Format(_("Changed '%s' to %s"),
|
||||
pTrack->GetName().
|
||||
c_str(),
|
||||
GetSampleFormatStr(newFormat)),
|
||||
_("Format Change"));
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = RefreshAll | FixScrollbars;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// Table class for a sub-menu
|
||||
class RateMenuTable : public PopupMenuTable
|
||||
{
|
||||
RateMenuTable() : mpData(NULL) {}
|
||||
DECLARE_POPUP_MENU(RateMenuTable);
|
||||
|
||||
public:
|
||||
static RateMenuTable &Instance();
|
||||
|
||||
private:
|
||||
void InitMenu(Menu *pMenu, void *pUserData) override;
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
mpData = NULL;
|
||||
}
|
||||
|
||||
TrackControls::InitMenuData *mpData;
|
||||
|
||||
int IdOfRate(int rate);
|
||||
void SetRate(WaveTrack * pTrack, double rate);
|
||||
|
||||
void OnRateChange(wxCommandEvent & event);
|
||||
void OnRateOther(wxCommandEvent & event);
|
||||
};
|
||||
|
||||
RateMenuTable &RateMenuTable::Instance()
|
||||
{
|
||||
static RateMenuTable instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void RateMenuTable::InitMenu(Menu *pMenu, void *pUserData)
|
||||
{
|
||||
mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
const auto rateId = IdOfRate((int)pTrack->GetRate());
|
||||
SetMenuChecks(*pMenu, [=](int id){ return id == rateId; });
|
||||
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
bool unsafe = project->IsAudioActive();
|
||||
for (int i = OnRate8ID; i <= OnRateOtherID; i++) {
|
||||
pMenu->Enable(i, !unsafe);
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(RateMenuTable)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate8ID, _("8000 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate11ID, _("11025 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate16ID, _("16000 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate22ID, _("22050 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate44ID, _("44100 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate48ID, _("48000 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate88ID, _("88200 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate96ID, _("96000 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate176ID, _("176400 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate192ID, _("192000 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate352ID, _("352800 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRate384ID, _("384000 Hz"), OnRateChange)
|
||||
POPUP_MENU_RADIO_ITEM(OnRateOtherID, _("&Other..."), OnRateOther)
|
||||
END_POPUP_MENU()
|
||||
|
||||
const int nRates = 12;
|
||||
|
||||
/// gRates MUST CORRESPOND DIRECTLY TO THE RATES AS LISTED IN THE MENU!!
|
||||
/// IN THE SAME ORDER!!
|
||||
static int gRates[nRates] = { 8000, 11025, 16000, 22050, 44100, 48000, 88200, 96000,
|
||||
176400, 192000, 352800, 384000 };
|
||||
|
||||
/// Converts a sampling rate to a wxWidgets menu item id
|
||||
int RateMenuTable::IdOfRate(int rate)
|
||||
{
|
||||
for (int i = 0; i<nRates; i++) {
|
||||
if (gRates[i] == rate)
|
||||
return i + OnRate8ID;
|
||||
}
|
||||
return OnRateOtherID;
|
||||
}
|
||||
|
||||
/// Sets the sample rate for a track, and if it is linked to
|
||||
/// another track, that one as well.
|
||||
void RateMenuTable::SetRate(WaveTrack * pTrack, double rate)
|
||||
{
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
TrackList *const tracks = project->GetTracks();
|
||||
pTrack->SetRate(rate);
|
||||
// Assume linked track is wave or null
|
||||
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
|
||||
if (partner)
|
||||
partner->SetRate(rate);
|
||||
// Separate conversion of "rate" enables changing the decimals without affecting i18n
|
||||
wxString rateString = wxString::Format(wxT("%.3f"), rate);
|
||||
project->PushState(wxString::Format(_("Changed '%s' to %s Hz"),
|
||||
pTrack->GetName().c_str(), rateString.c_str()),
|
||||
_("Rate Change"));
|
||||
}
|
||||
|
||||
/// This method handles the selection from the Rate
|
||||
/// submenu of the track menu, except for "Other" (/see OnRateOther).
|
||||
void RateMenuTable::OnRateChange(wxCommandEvent & event)
|
||||
{
|
||||
int id = event.GetId();
|
||||
wxASSERT(id >= OnRate8ID && id <= OnRate384ID);
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
wxASSERT(pTrack->GetKind() == Track::Wave);
|
||||
|
||||
SetRate(pTrack, gRates[id - OnRate8ID]);
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = RefreshAll | FixScrollbars;
|
||||
}
|
||||
|
||||
void RateMenuTable::OnRateOther(wxCommandEvent &)
|
||||
{
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
wxASSERT(pTrack && pTrack->GetKind() == Track::Wave);
|
||||
|
||||
int newRate;
|
||||
|
||||
/// \todo Remove artificial constants!!
|
||||
/// \todo Make a real dialog box out of this!!
|
||||
while (true)
|
||||
{
|
||||
wxDialogWrapper dlg(mpData->pParent, wxID_ANY, wxString(_("Set Rate")));
|
||||
dlg.SetName(dlg.GetTitle());
|
||||
ShuttleGui S(&dlg, eIsCreating);
|
||||
wxString rate;
|
||||
wxArrayString rates;
|
||||
wxComboBox *cb;
|
||||
|
||||
rate.Printf(wxT("%ld"), lrint(pTrack->GetRate()));
|
||||
|
||||
rates.Add(wxT("8000"));
|
||||
rates.Add(wxT("11025"));
|
||||
rates.Add(wxT("16000"));
|
||||
rates.Add(wxT("22050"));
|
||||
rates.Add(wxT("44100"));
|
||||
rates.Add(wxT("48000"));
|
||||
rates.Add(wxT("88200"));
|
||||
rates.Add(wxT("96000"));
|
||||
rates.Add(wxT("176400"));
|
||||
rates.Add(wxT("192000"));
|
||||
rates.Add(wxT("352800"));
|
||||
rates.Add(wxT("384000"));
|
||||
|
||||
S.StartVerticalLay(true);
|
||||
{
|
||||
S.SetBorder(10);
|
||||
S.StartHorizontalLay(wxEXPAND, false);
|
||||
{
|
||||
cb = S.AddCombo(_("New sample rate (Hz):"),
|
||||
rate,
|
||||
&rates);
|
||||
#if defined(__WXMAC__)
|
||||
// As of wxMac-2.8.12, setting manually is required
|
||||
// to handle rates not in the list. See: Bug #427
|
||||
cb->SetValue(rate);
|
||||
#endif
|
||||
}
|
||||
S.EndHorizontalLay();
|
||||
S.AddStandardButtons();
|
||||
}
|
||||
S.EndVerticalLay();
|
||||
|
||||
dlg.SetClientSize(dlg.GetSizer()->CalcMin());
|
||||
dlg.Center();
|
||||
|
||||
if (dlg.ShowModal() != wxID_OK)
|
||||
{
|
||||
return; // user cancelled dialog
|
||||
}
|
||||
|
||||
long lrate;
|
||||
if (cb->GetValue().ToLong(&lrate) && lrate >= 1 && lrate <= 1000000)
|
||||
{
|
||||
newRate = (int)lrate;
|
||||
break;
|
||||
}
|
||||
|
||||
wxMessageBox(_("The entered value is invalid"), _("Error"),
|
||||
wxICON_ERROR, mpData->pParent);
|
||||
}
|
||||
|
||||
SetRate(pTrack, newRate);
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = RefreshAll | FixScrollbars;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Class defining common command handlers for mono and stereo tracks
|
||||
class WaveTrackMenuTable : public PopupMenuTable
|
||||
{
|
||||
WaveTrackMenuTable() : mpData(NULL) {}
|
||||
DECLARE_POPUP_MENU(WaveTrackMenuTable);
|
||||
|
||||
public:
|
||||
static WaveTrackMenuTable &Instance();
|
||||
|
||||
void InitMenu(Menu*, void *pUserData) override
|
||||
{
|
||||
mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
|
||||
}
|
||||
protected:
|
||||
WaveTrackMenuTable() : mpData(NULL) {}
|
||||
|
||||
void InitMenu(Menu *pMenu, void *pUserData) override;
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
mpData = nullptr;
|
||||
}
|
||||
|
||||
DECLARE_POPUP_MENU(WaveTrackMenuTable);
|
||||
|
||||
TrackControls::InitMenuData *mpData;
|
||||
|
||||
void OnSetDisplay(wxCommandEvent & event);
|
||||
void OnSpectrogramSettings(wxCommandEvent & event);
|
||||
|
||||
void OnChannelChange(wxCommandEvent & event);
|
||||
void OnMergeStereo(wxCommandEvent & event);
|
||||
|
||||
void SplitStereo(bool stereo);
|
||||
|
||||
void OnSwapChannels(wxCommandEvent & event);
|
||||
void OnSplitStereo(wxCommandEvent & event);
|
||||
void OnSplitStereoMono(wxCommandEvent & event);
|
||||
};
|
||||
|
||||
WaveTrackMenuTable &WaveTrackMenuTable::Instance()
|
||||
@ -94,10 +485,435 @@ WaveTrackMenuTable &WaveTrackMenuTable::Instance()
|
||||
return instance;
|
||||
}
|
||||
|
||||
void WaveTrackMenuTable::InitMenu(Menu *pMenu, void *pUserData)
|
||||
{
|
||||
mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
|
||||
std::vector<int> checkedIds;
|
||||
|
||||
const int display = pTrack->GetDisplay();
|
||||
checkedIds.push_back(
|
||||
display == WaveTrack::Waveform
|
||||
? (pTrack->GetWaveformSettings().isLinear()
|
||||
? OnWaveformID : OnWaveformDBID)
|
||||
: OnSpectrumID);
|
||||
|
||||
// Bug 1253. Shouldn't open preferences if audio is busy.
|
||||
// We can't change them on the fly yet anyway.
|
||||
const bool bAudioBusy = gAudioIO->IsBusy();
|
||||
pMenu->Enable(OnSpectrogramSettingsID,
|
||||
(display == WaveTrack::Spectrum) && !bAudioBusy);
|
||||
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
bool unsafe = EffectManager::Get().RealtimeIsActive() &&
|
||||
project->IsAudioActive();
|
||||
|
||||
const bool isMono = !pTrack->GetLink();
|
||||
if ( isMono )
|
||||
{
|
||||
mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
|
||||
TrackList *const tracks = project->GetTracks();
|
||||
Track *const next = tracks->GetNext(pTrack);
|
||||
|
||||
if (isMono) {
|
||||
const bool canMakeStereo =
|
||||
(next && !next->GetLinked()
|
||||
&& pTrack->GetKind() == Track::Wave
|
||||
&& next->GetKind() == Track::Wave);
|
||||
pMenu->Enable(OnMergeStereoID, canMakeStereo && !unsafe);
|
||||
|
||||
int itemId;
|
||||
switch (pTrack->GetChannel()) {
|
||||
case Track::LeftChannel:
|
||||
itemId = OnChannelLeftID;
|
||||
break;
|
||||
case Track::RightChannel:
|
||||
itemId = OnChannelRightID;
|
||||
break;
|
||||
default:
|
||||
itemId = OnChannelMonoID;
|
||||
break;
|
||||
}
|
||||
checkedIds.push_back(itemId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pMenu->Enable(OnMergeStereoID, false);
|
||||
}
|
||||
|
||||
SetMenuChecks(*pMenu, [&](int id){
|
||||
auto end = checkedIds.end();
|
||||
return end != std::find(checkedIds.begin(), end, id);
|
||||
});
|
||||
|
||||
|
||||
pMenu->Enable(OnSwapChannelsID, !isMono && !unsafe);
|
||||
pMenu->Enable(OnSplitStereoID, !isMono && !unsafe);
|
||||
|
||||
// Several menu items no longer needed....
|
||||
#if 0
|
||||
pMenu->Enable(OnSplitStereoMonoID, !isMono && !unsafe);
|
||||
pMenu->Enable(OnChannelMonoID, isMono);
|
||||
pMenu->Enable(OnChannelLeftID, isMono);
|
||||
pMenu->Enable(OnChannelRightID, isMono);
|
||||
#endif
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(WaveTrackMenuTable)
|
||||
POPUP_MENU_SEPARATOR()
|
||||
|
||||
POPUP_MENU_RADIO_ITEM(OnWaveformID, _("Wa&veform"), OnSetDisplay)
|
||||
POPUP_MENU_RADIO_ITEM(OnWaveformDBID, _("&Waveform (dB)"), OnSetDisplay)
|
||||
POPUP_MENU_RADIO_ITEM(OnSpectrumID, _("&Spectrogram"), OnSetDisplay)
|
||||
POPUP_MENU_ITEM(OnSpectrogramSettingsID, _("S&pectrogram Settings..."), OnSpectrogramSettings)
|
||||
POPUP_MENU_SEPARATOR()
|
||||
|
||||
// POPUP_MENU_RADIO_ITEM(OnChannelMonoID, _("&Mono"), OnChannelChange)
|
||||
// POPUP_MENU_RADIO_ITEM(OnChannelLeftID, _("&Left Channel"), OnChannelChange)
|
||||
// POPUP_MENU_RADIO_ITEM(OnChannelRightID, _("R&ight Channel"), OnChannelChange)
|
||||
POPUP_MENU_ITEM(OnMergeStereoID, _("Make &Stereo"), OnMergeStereo)
|
||||
|
||||
POPUP_MENU_ITEM(OnSwapChannelsID, _("S&wap"), OnSwapChannels)
|
||||
POPUP_MENU_ITEM(OnSplitStereoID, _("S&plit"), OnSplitStereo)
|
||||
// DA: Uses split stereo track and then drag pan sliders for split-stereo-to-mono
|
||||
#ifndef EXPERIMENTAL_DA
|
||||
POPUP_MENU_ITEM(OnSplitStereoMonoID, _("Split Stereo to &Mono"), OnSplitStereoMono)
|
||||
#endif
|
||||
POPUP_MENU_SEPARATOR()
|
||||
|
||||
POPUP_MENU_SUB_MENU(0, _("&Format"), FormatMenuTable)
|
||||
POPUP_MENU_SEPARATOR()
|
||||
POPUP_MENU_SUB_MENU(0, _("Rat&e"), RateMenuTable)
|
||||
END_POPUP_MENU()
|
||||
|
||||
PopupMenuTable *WaveTrackControls::GetMenuExtension(Track*)
|
||||
|
||||
/// Set the Display mode based on the menu choice in the Track Menu.
|
||||
void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event)
|
||||
{
|
||||
int idInt = event.GetId();
|
||||
wxASSERT(idInt >= OnWaveformID && idInt <= OnSpectrumID);
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
wxASSERT(pTrack && pTrack->GetKind() == Track::Wave);
|
||||
|
||||
bool linear = false;
|
||||
WaveTrack::WaveTrackDisplay id;
|
||||
switch (idInt) {
|
||||
default:
|
||||
case OnWaveformID:
|
||||
linear = true, id = WaveTrack::Waveform; break;
|
||||
case OnWaveformDBID:
|
||||
id = WaveTrack::Waveform; break;
|
||||
case OnSpectrumID:
|
||||
id = WaveTrack::Spectrum; break;
|
||||
}
|
||||
|
||||
const bool wrongType = pTrack->GetDisplay() != id;
|
||||
const bool wrongScale =
|
||||
(id == WaveTrack::Waveform &&
|
||||
pTrack->GetWaveformSettings().isLinear() != linear);
|
||||
if (wrongType || wrongScale) {
|
||||
pTrack->SetLastScaleType();
|
||||
pTrack->SetDisplay(WaveTrack::WaveTrackDisplay(id));
|
||||
if (wrongScale)
|
||||
pTrack->GetIndependentWaveformSettings().scaleType = linear
|
||||
? WaveformSettings::stLinear
|
||||
: WaveformSettings::stLogarithmic;
|
||||
|
||||
// Assume partner is wave or null
|
||||
auto partner = static_cast<WaveTrack *>(pTrack->GetLink());
|
||||
if (partner) {
|
||||
partner->SetLastScaleType();
|
||||
partner->SetDisplay(WaveTrack::WaveTrackDisplay(id));
|
||||
if (wrongScale)
|
||||
partner->GetIndependentWaveformSettings().scaleType = linear
|
||||
? WaveformSettings::stLinear
|
||||
: WaveformSettings::stLogarithmic;
|
||||
}
|
||||
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
||||
if (pTrack->GetDisplay() == WaveTrack::Waveform) {
|
||||
pTrack->SetVirtualState(false);
|
||||
}
|
||||
else if (id == WaveTrack::Waveform) {
|
||||
pTrack->SetVirtualState(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
project->ModifyState(true);
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = RefreshAll | UpdateVRuler;
|
||||
}
|
||||
}
|
||||
|
||||
void WaveTrackMenuTable::OnSpectrogramSettings(wxCommandEvent &)
|
||||
{
|
||||
class ViewSettingsDialog final : public PrefsDialog
|
||||
{
|
||||
public:
|
||||
ViewSettingsDialog
|
||||
(wxWindow *parent, const wxString &title, PrefsDialog::Factories &factories,
|
||||
int page)
|
||||
: PrefsDialog(parent, title, factories)
|
||||
, mPage(page)
|
||||
{
|
||||
}
|
||||
|
||||
long GetPreferredPage() override
|
||||
{
|
||||
return mPage;
|
||||
}
|
||||
|
||||
void SavePreferredPage() override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const int mPage;
|
||||
};
|
||||
|
||||
if (gAudioIO->IsBusy()){
|
||||
wxMessageBox(_("To change Spectrogram Settings, stop any\n"
|
||||
"playing or recording first."),
|
||||
_("Stop the Audio First"), wxOK | wxICON_EXCLAMATION | wxCENTRE);
|
||||
return;
|
||||
}
|
||||
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
// WaveformPrefsFactory waveformFactory(pTrack);
|
||||
// TracksBehaviorsPrefsFactory tracksBehaviorsFactory();
|
||||
SpectrumPrefsFactory spectrumFactory(pTrack);
|
||||
|
||||
PrefsDialog::Factories factories;
|
||||
// factories.push_back(&waveformFactory);
|
||||
factories.push_back(&spectrumFactory);
|
||||
const int page =
|
||||
// (pTrack->GetDisplay() == WaveTrack::Spectrum) ? 1 :
|
||||
0;
|
||||
|
||||
wxString title(pTrack->GetName() + wxT(": "));
|
||||
ViewSettingsDialog dialog(mpData->pParent, title, factories, page);
|
||||
|
||||
if (0 != dialog.ShowModal()) {
|
||||
// Redraw
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
project->ModifyState(true);
|
||||
mpData->result = RefreshCode::RefreshAll;
|
||||
}
|
||||
}
|
||||
|
||||
void WaveTrackMenuTable::OnChannelChange(wxCommandEvent & event)
|
||||
{
|
||||
int id = event.GetId();
|
||||
wxASSERT(id >= OnChannelLeftID && id <= OnChannelMonoID);
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
wxASSERT(pTrack);
|
||||
int channel;
|
||||
wxString channelmsg;
|
||||
switch (id) {
|
||||
default:
|
||||
case OnChannelMonoID:
|
||||
channel = Track::MonoChannel;
|
||||
channelmsg = _("Mono");
|
||||
break;
|
||||
case OnChannelLeftID:
|
||||
channel = Track::LeftChannel;
|
||||
channelmsg = _("Left Channel");
|
||||
break;
|
||||
case OnChannelRightID:
|
||||
channel = Track::RightChannel;
|
||||
channelmsg = _("Right Channel");
|
||||
break;
|
||||
}
|
||||
pTrack->SetChannel(channel);
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
project->PushState(wxString::Format(_("Changed '%s' to %s"),
|
||||
pTrack->GetName().c_str(),
|
||||
channelmsg),
|
||||
_("Channel"));
|
||||
mpData->result = RefreshCode::RefreshAll;
|
||||
}
|
||||
|
||||
/// Merge two tracks into one stereo track ??
|
||||
void WaveTrackMenuTable::OnMergeStereo(wxCommandEvent &)
|
||||
{
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
wxASSERT(pTrack);
|
||||
pTrack->SetLinked(true);
|
||||
// Assume partner is wave or null
|
||||
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
|
||||
|
||||
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
||||
if (MONO_WAVE_PAN(pTrack))
|
||||
pTrack->SetVirtualState(false);
|
||||
if (MONO_WAVE_PAN(partner))
|
||||
static_cast<WaveTrack*>(partner)->SetVirtualState(false);
|
||||
#endif
|
||||
|
||||
if (partner) {
|
||||
// Set partner's parameters to match target.
|
||||
partner->Merge(*pTrack);
|
||||
|
||||
pTrack->SetPan( 0.0f );
|
||||
pTrack->SetChannel(Track::LeftChannel);
|
||||
partner->SetPan( 0.0f );
|
||||
partner->SetChannel(Track::RightChannel);
|
||||
|
||||
// Set NEW track heights and minimized state
|
||||
bool bBothMinimizedp = ((pTrack->GetMinimized()) && (partner->GetMinimized()));
|
||||
pTrack->SetMinimized(false);
|
||||
partner->SetMinimized(false);
|
||||
int AverageHeight = (pTrack->GetHeight() + partner->GetHeight()) / 2;
|
||||
pTrack->SetHeight(AverageHeight);
|
||||
partner->SetHeight(AverageHeight);
|
||||
pTrack->SetMinimized(bBothMinimizedp);
|
||||
partner->SetMinimized(bBothMinimizedp);
|
||||
|
||||
//On Demand - join the queues together.
|
||||
if (ODManager::IsInstanceCreated())
|
||||
if (!ODManager::Instance()->MakeWaveTrackDependent(partner, pTrack))
|
||||
{
|
||||
;
|
||||
//TODO: in the future, we will have to check the return value of MakeWaveTrackDependent -
|
||||
//if the tracks cannot merge, it returns false, and in that case we should not allow a merging.
|
||||
//for example it returns false when there are two different types of ODTasks on each track's queue.
|
||||
//we will need to display this to the user.
|
||||
}
|
||||
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
project->PushState(wxString::Format(_("Made '%s' a stereo track"),
|
||||
pTrack->GetName().
|
||||
c_str()),
|
||||
_("Make Stereo"));
|
||||
}
|
||||
else
|
||||
pTrack->SetLinked(false);
|
||||
|
||||
mpData->result = RefreshCode::RefreshAll;
|
||||
}
|
||||
|
||||
/// Split a stereo track into two tracks...
|
||||
void WaveTrackMenuTable::SplitStereo(bool stereo)
|
||||
{
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
wxASSERT(pTrack);
|
||||
|
||||
if (stereo)
|
||||
pTrack->SetPanFromChannelType();
|
||||
pTrack->SetChannel(Track::MonoChannel);
|
||||
|
||||
// Assume partner is present, and is wave
|
||||
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
|
||||
wxASSERT(partner);
|
||||
if (!partner)
|
||||
return;
|
||||
|
||||
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
||||
if (!stereo && MONO_WAVE_PAN(pTrack))
|
||||
pTrack->SetVirtualState(true, true);
|
||||
if (!stereo && MONO_WAVE_PAN(partner))
|
||||
partner->SetVirtualState(true, true);
|
||||
#endif
|
||||
|
||||
if (partner)
|
||||
{
|
||||
// Keep original stereo track name.
|
||||
partner->SetName(pTrack->GetName());
|
||||
if (stereo)
|
||||
partner->SetPanFromChannelType();
|
||||
partner->SetChannel(Track::MonoChannel);
|
||||
|
||||
//On Demand - have each channel add its own.
|
||||
if (ODManager::IsInstanceCreated() && partner->GetKind() == Track::Wave)
|
||||
ODManager::Instance()->MakeWaveTrackIndependent(partner);
|
||||
}
|
||||
|
||||
pTrack->SetLinked(false);
|
||||
//make sure neither track is smaller than its minimum height
|
||||
if (pTrack->GetHeight() < pTrack->GetMinimizedHeight())
|
||||
pTrack->SetHeight(pTrack->GetMinimizedHeight());
|
||||
if (partner)
|
||||
{
|
||||
if (partner->GetHeight() < partner->GetMinimizedHeight())
|
||||
partner->SetHeight(partner->GetMinimizedHeight());
|
||||
|
||||
// Make tracks the same height
|
||||
if (pTrack->GetHeight() != partner->GetHeight())
|
||||
{
|
||||
pTrack->SetHeight((pTrack->GetHeight() + partner->GetHeight()) / 2.0);
|
||||
partner->SetHeight(pTrack->GetHeight());
|
||||
}
|
||||
}
|
||||
|
||||
mpData->result = RefreshCode::RefreshAll;
|
||||
}
|
||||
|
||||
/// Swap the left and right channels of a stero track...
|
||||
void WaveTrackMenuTable::OnSwapChannels(wxCommandEvent &)
|
||||
{
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
// Assume partner is wave or null
|
||||
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
|
||||
Track *const focused = project->GetTrackPanel()->GetFocusedTrack();
|
||||
const bool hasFocus =
|
||||
(focused == pTrack || focused == partner);
|
||||
|
||||
SplitStereo(false);
|
||||
pTrack->SetChannel(Track::RightChannel);
|
||||
partner->SetChannel(Track::LeftChannel);
|
||||
|
||||
TrackList *const tracks = project->GetTracks();
|
||||
(tracks->MoveUp(partner));
|
||||
partner->SetLinked(true);
|
||||
|
||||
MixerBoard* pMixerBoard = project->GetMixerBoard();
|
||||
if (pMixerBoard)
|
||||
pMixerBoard->UpdateTrackClusters();
|
||||
|
||||
if (hasFocus)
|
||||
project->GetTrackPanel()->SetFocusedTrack(partner);
|
||||
|
||||
project->PushState(wxString::Format(_("Swapped Channels in '%s'"),
|
||||
pTrack->GetName().c_str()),
|
||||
_("Swap Channels"));
|
||||
|
||||
mpData->result = RefreshCode::RefreshAll;
|
||||
}
|
||||
|
||||
/// Split a stereo track into two tracks...
|
||||
void WaveTrackMenuTable::OnSplitStereo(wxCommandEvent &)
|
||||
{
|
||||
SplitStereo(true);
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
project->PushState(wxString::Format(_("Split stereo track '%s'"),
|
||||
pTrack->GetName().c_str()),
|
||||
_("Split"));
|
||||
|
||||
mpData->result = RefreshCode::RefreshAll;
|
||||
}
|
||||
|
||||
/// Split a stereo track into two mono tracks...
|
||||
void WaveTrackMenuTable::OnSplitStereoMono(wxCommandEvent &)
|
||||
{
|
||||
SplitStereo(false);
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
AudacityProject *const project = ::GetActiveProject();
|
||||
project->PushState(wxString::Format(_("Split Stereo to Mono '%s'"),
|
||||
pTrack->GetName().c_str()),
|
||||
_("Split to Mono"));
|
||||
|
||||
mpData->result = RefreshCode::RefreshAll;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
PopupMenuTable *WaveTrackControls::GetMenuExtension(Track *pTrack)
|
||||
{
|
||||
return &WaveTrackMenuTable::Instance();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user