1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-02 08:39:46 +02:00

More rewrites of iterations over channels...

... that can generalize to more than stereo
This commit is contained in:
Paul Licameli 2018-09-30 11:00:06 -04:00
commit 3561154311
17 changed files with 248 additions and 308 deletions

View File

@ -2051,25 +2051,6 @@ void AudacityProject::FixScrollbars()
GetTrackPanel()->HandleCursorForPresentMouseState(); } );
}
std::shared_ptr<Track> AudacityProject::GetFirstVisible()
{
std::shared_ptr<Track> pTrack;
if (GetTracks()) {
TrackListIterator iter(GetTracks());
for (Track *t = iter.First(); t; t = iter.Next()) {
int y = t->GetY();
int h = t->GetHeight();
if (y + h - 1 >= mViewInfo.vpos) {
// At least the bottom row of pixels is not scrolled away above
pTrack = Track::Pointer(t);
break;
}
}
}
return pTrack;
}
void AudacityProject::UpdateLayout()
{
if (!mTrackPanel)
@ -4232,23 +4213,35 @@ AudacityProject::AddImportedTracks(const wxString &fileName,
bool initiallyEmpty = mTracks->empty();
double newRate = 0;
wxString trackNameBase = fileName.AfterLast(wxFILE_SEP_PATH).BeforeLast('.');
bool isLinked = false;
int i = -1;
for (auto &uNewTrack : newTracks) {
++i;
// Must add all tracks first (before using Track::IsLeader)
for (auto &uNewTrack : newTracks) {
auto newTrack = mTracks->Add(std::move(uNewTrack));
results.push_back(Track::Pointer(newTrack));
}
newTracks.clear();
// Now name them
// Add numbers to track names only if there is more than one (mono or stereo)
// track (not necessarily, more than one channel)
const bool useSuffix =
make_iterator_range( results.begin() + 1, results.end() )
.any_of( []( decltype(*results.begin()) &pTrack )
{ return pTrack->IsLeader(); } );
for (const auto &newTrack : results) {
if ( newTrack->IsLeader() )
// Count groups only
++i;
newTrack->SetSelected(true);
//we need to check link status based on the first channel only.
if(0==i)
isLinked = newTrack->GetLinked();
if (numTracks > 2 || (numTracks > 1 && !isLinked) ) {
if ( useSuffix )
newTrack->SetName(trackNameBase + wxString::Format(wxT(" %d" ), i + 1));
}
else {
else
newTrack->SetName(trackNameBase);
}
newTrack->TypeSwitch( [&](WaveTrack *wt) {
if (newRate == 0)
@ -4299,8 +4292,6 @@ AudacityProject::AddImportedTracks(const wxString &fileName,
// Moved this call to higher levels to prevent flicker redrawing everything on each file.
// HandleResize();
newTracks.clear();
return results;
}

View File

@ -213,8 +213,6 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame,
const ViewInfo &GetViewInfo() const { return mViewInfo; }
ViewInfo &GetViewInfo() { return mViewInfo; }
std::shared_ptr<Track> GetFirstVisible();
void GetPlayRegion(double* playRegionStart, double *playRegionEnd);
bool IsPlayRegionLocked() { return mLockPlayRegion; }
void SetPlayRegionLocked(bool value) { mLockPlayRegion = value; }

View File

@ -341,7 +341,6 @@ void TrackArtist::SetMargins(int left, int top, int right, int bottom)
void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
const TrackList * tracks,
Track * start,
const wxRegion & reg,
const wxRect & rect,
const wxRect & clip,
@ -351,13 +350,11 @@ void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
bool bigPoints,
bool drawSliders)
{
// Copy the horizontal extent of rect; will later change only the vertical.
wxRect trackRect = rect;
wxRect stereoTrackRect;
TrackListConstIterator iter(tracks);
const Track *t;
bool hasSolo = false;
for (t = iter.First(); t; t = iter.Next()) {
for (const Track *t : *tracks) {
t = t->SubstitutePendingChangedTrack().get();
auto pt = dynamic_cast<const PlayableTrack *>(t);
if (pt && pt->GetSolo()) {
@ -381,60 +378,52 @@ void TrackArtist::DrawTracks(TrackPanelDrawingContext &context,
gPrefs->Read(wxT("/GUI/ShowTrackNameInWaveform"), &mbShowTrackNameInWaveform, false);
t = iter.StartWith(start);
while (t) {
t = t->SubstitutePendingChangedTrack().get();
trackRect.y = t->GetY() - zoomInfo.vpos;
trackRect.height = t->GetHeight();
for(auto leader : tracks->Leaders()) {
auto group = TrackList::Channels( leader );
leader = leader->SubstitutePendingChangedTrack().get();
if (trackRect.y > clip.GetBottom() && !t->GetLinked()) {
trackRect.y = leader->GetY() - zoomInfo.vpos;
trackRect.height = group.sum( [&] (const Track *channel) {
channel = channel->SubstitutePendingChangedTrack().get();
return channel->GetHeight();
});
if (trackRect.GetBottom() < clip.GetTop())
continue;
else if (trackRect.GetTop() > clip.GetBottom())
break;
}
for (auto t : group) {
t = t->SubstitutePendingChangedTrack().get();
#if defined(DEBUG_CLIENT_AREA)
// Filled rectangle to show the interior of the client area
wxRect zr = trackRect;
zr.x+=1; zr.y+=5; zr.width-=7; zr.height-=7;
dc.SetPen(*wxCYAN_PEN);
dc.SetBrush(*wxRED_BRUSH);
dc.DrawRectangle(zr);
// Filled rectangle to show the interior of the client area
wxRect zr = trackRect;
zr.x+=1; zr.y+=5; zr.width-=7; zr.height-=7;
dc.SetPen(*wxCYAN_PEN);
dc.SetBrush(*wxRED_BRUSH);
dc.DrawRectangle(zr);
#endif
stereoTrackRect = trackRect;
// For various reasons, the code will break if we display one
// of a stereo pair of tracks but not the other - for example,
// if you try to edit the envelope of one track when its linked
// pair is off the screen, then it won't be able to edit the
// offscreen envelope. So we compute the rect of the track and
// its linked partner, and see if any part of that rect is on-screen.
// If so, we draw both. Otherwise, we can safely draw neither.
// For various reasons, the code will break if we display one
// of a stereo pair of tracks but not the other - for example,
// if you try to edit the envelope of one track when its linked
// pair is off the screen, then it won't be able to edit the
// offscreen envelope. So we compute the rect of the track and
// its linked partner, and see if any part of that rect is on-screen.
// If so, we draw both. Otherwise, we can safely draw neither.
Track *link = t->GetLink();
if (link) {
if (t->GetLinked()) {
// If we're the first track
stereoTrackRect.height += link->GetHeight();
}
else {
// We're the second of two
stereoTrackRect.y -= link->GetHeight();
stereoTrackRect.height += link->GetHeight();
if (trackRect.Intersects(clip) && reg.Contains(trackRect)) {
wxRect rr = trackRect;
rr.x += mMarginLeft;
rr.y += mMarginTop;
rr.width -= (mMarginLeft + mMarginRight);
rr.height -= (mMarginTop + mMarginBottom);
DrawTrack(context, t, rr,
selectedRegion, zoomInfo,
drawEnvelope, bigPoints, drawSliders, hasSolo);
}
}
if (stereoTrackRect.Intersects(clip) && reg.Contains(stereoTrackRect)) {
wxRect rr = trackRect;
rr.x += mMarginLeft;
rr.y += mMarginTop;
rr.width -= (mMarginLeft + mMarginRight);
rr.height -= (mMarginTop + mMarginBottom);
DrawTrack(context, t, rr,
selectedRegion, zoomInfo,
drawEnvelope, bigPoints, drawSliders, hasSolo);
}
t = iter.Next();
}
}
@ -480,8 +469,7 @@ void TrackArtist::DrawTrack(TrackPanelDrawingContext &context,
#endif
if (mbShowTrackNameInWaveform &&
// Exclude right channel of stereo track
!(!wt->GetLinked() && wt->GetLink()) &&
wt->IsLeader() &&
// Exclude empty name.
!wt->GetName().IsEmpty()) {
wxBrush Brush;

View File

@ -55,7 +55,7 @@ class AUDACITY_DLL_API TrackArtist {
void SetColours(int iColorIndex);
void DrawTracks(TrackPanelDrawingContext &context,
const TrackList *tracks, Track *start,
const TrackList *tracks,
const wxRegion & reg,
const wxRect & rect, const wxRect & clip,
const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo,

View File

@ -1156,8 +1156,7 @@ void TrackPanel::DrawTracks(wxDC * dc)
TrackPanelDrawingContext context{ *dc, Target(), mLastMouseState };
// The track artist actually draws the stuff inside each track
auto first = GetProject()->GetFirstVisible();
mTrackArtist->DrawTracks(context, GetTracks(), first.get(),
mTrackArtist->DrawTracks(context, GetTracks(),
region, tracksRect, clip,
mViewInfo->selectedRegion, *mViewInfo,
envelopeFlag, bigPointsFlag, sliderFlag);
@ -1847,14 +1846,12 @@ void TrackPanel::UpdateTrackVRuler(const Track *t)
wxRect rect(GetVRulerOffset(),
kTopMargin,
GetVRulerWidth(),
t->GetHeight() - (kTopMargin + kBottomMargin));
0);
mTrackArtist->UpdateVRuler(t, rect);
const Track *l = t->GetLink();
if (l)
{
rect.height = l->GetHeight() - (kTopMargin + kBottomMargin);
mTrackArtist->UpdateVRuler(l, rect);
for (auto channel : TrackList::Channels(t)) {
rect.height = channel->GetHeight() - (kTopMargin + kBottomMargin);
mTrackArtist->UpdateVRuler(channel, rect);
}
}
@ -2080,30 +2077,29 @@ wxRect TrackPanel::FindTrackRect( const Track * target, bool label )
return { 0, 0, 0, 0 };
}
wxRect rect{
0,
target->GetY() - mViewInfo->vpos,
GetSize().GetWidth(),
target->GetHeight()
};
// PRL: I think the following very old comment misused the term "race
// condition" for a bug that happened with only a single thread. I think the
// real problem referred to, was that this function could be reached, via
// TrackPanelAx callbacks, during low-level operations while the TrackList
// was not in a consistent state. Therefore GetLinked() did not imply
// that GetLink() was not null.
// was not in a consistent state.
// Now the problem is fixed by delaying the handling of events generated
// by TrackList.
// by TrackList. And besides that, we use Channels() instead of looking
// directly at the links.
// Old comment:
// The check for a null linked track is necessary because there's
// a possible race condition between the time the 2 linked tracks
// are added and when wxAccessible methods are called. This is
// most evident when using Jaws.
if (target->GetLinked() && target->GetLink()) {
rect.height += target->GetLink()->GetHeight();
}
auto height = TrackList::Channels( target ).sum( &Track::GetHeight );
wxRect rect{
0,
target->GetY() - mViewInfo->vpos,
GetSize().GetWidth(),
height
};
rect.x += kLeftMargin;
if (label)
@ -2151,8 +2147,7 @@ void TrackPanel::SetFocusedCell()
void TrackPanel::SetFocusedTrack( Track *t )
{
// Make sure we always have the first linked track of a stereo track
if (t && !t->GetLinked() && t->GetLink())
t = (WaveTrack*)t->GetLink();
t = *GetTracks()->FindLeader(t);
auto cell = mAx->SetFocus( Track::Pointer( t ) ).get();
@ -2657,7 +2652,7 @@ TrackPanelCellIterator &TrackPanelCellIterator::operator++ ()
}
if ( mpTrack ) {
if ( mType == CellType::Label &&
mpTrack->GetLink() && !mpTrack->GetLinked() )
!mpTrack->IsLeader() )
// Visit label of stereo track only once
++mType;
switch ( mType ) {
@ -2723,10 +2718,10 @@ void TrackPanelCellIterator::UpdateRect()
mRect.x = kLeftMargin;
mRect.width = kTrackInfoWidth - mRect.x;
mRect.y += kTopMargin;
mRect.height =
TrackList::Channels(mpTrack.get())
.sum( &Track::GetHeight );
mRect.height -= (kBottomMargin + kTopMargin);
auto partner = mpTrack->GetLink();
if ( partner && mpTrack->GetLinked() )
mRect.height += partner->GetHeight();
break;
}
case CellType::VRuler:
@ -2742,11 +2737,12 @@ void TrackPanelCellIterator::UpdateRect()
// The resizer region encompasses the bottom margin proper to this
// track, plus the top margin of the next track (or, an equally
// tall zone below, in case there is no next track)
auto partner = mpTrack->GetLink();
if ( partner && mpTrack->GetLinked() )
mRect.x = kTrackInfoWidth;
else
if ( mpTrack.get() ==
*TrackList::Channels(mpTrack.get()).rbegin() )
// Last channel has a resizer extending farther leftward
mRect.x = kLeftMargin;
else
mRect.x = kTrackInfoWidth;
mRect.width -= (mRect.x + kRightMargin);
mRect.y += (mRect.height - kBottomMargin);
mRect.height = (kBottomMargin + kTopMargin);

View File

@ -144,13 +144,9 @@ bool TrackPanelAx::IsFocused( const Track *track )
if (origTrack)
track = origTrack;
if( ( track == focusedTrack.get() ) ||
( focusedTrack && track == focusedTrack->GetLink() ) )
{
return true;
}
return false;
return focusedTrack
? TrackList::Channels(focusedTrack.get()).contains(track)
: !track;
}
int TrackPanelAx::TrackNum( const std::shared_ptr<Track> &target )

View File

@ -143,8 +143,6 @@ UIHandle::Result CutlineHandle::Click
// Cutline data changed on either branch, so refresh the track display.
UIHandle::Result result = RefreshCell;
// Assume linked track is wave or null
const auto linked = static_cast<WaveTrack*>(mpTrack->GetLink());
if (event.LeftDown())
{
@ -156,26 +154,30 @@ UIHandle::Result CutlineHandle::Click
// When user presses left button on cut line, expand the line again
double cutlineStart = 0, cutlineEnd = 0;
double *pCutlineStart = &cutlineStart, *pCutlineEnd = &cutlineEnd;
mpTrack->ExpandCutLine(mLocation.pos, &cutlineStart, &cutlineEnd);
if (linked)
// Expand the cutline in the opposite channel if it is present.
linked->ExpandCutLine(mLocation.pos);
for (auto channel :
TrackList::Channels(mpTrack.get())) {
channel->ExpandCutLine(
mLocation.pos, pCutlineStart, pCutlineEnd);
if ( channel == mpTrack.get() )
pCutlineStart = pCutlineEnd = nullptr;
}
viewInfo.selectedRegion.setTimes(cutlineStart, cutlineEnd);
result |= UpdateSelection;
}
else if (mLocation.typ == WaveTrackLocation::locationMergePoint) {
const double pos = mLocation.pos;
mpTrack->MergeClips(mLocation.clipidx1, mLocation.clipidx2);
if (linked) {
for (auto channel :
TrackList::Channels(mpTrack.get())) {
// Don't assume correspondence of merge points across channels!
int idx = FindMergeLine(linked, pos);
int idx = FindMergeLine(channel, pos);
if (idx >= 0) {
WaveTrack::Location location = linked->GetCachedLocations()[idx];
linked->MergeClips(location.clipidx1, location.clipidx2);
WaveTrack::Location location =
channel->GetCachedLocations()[idx];
channel->MergeClips(
location.clipidx1, location.clipidx2);
}
}
@ -184,10 +186,10 @@ UIHandle::Result CutlineHandle::Click
}
else if (event.RightDown())
{
bool removed = mpTrack->RemoveCutLine(mLocation.pos);
if (linked)
removed = linked->RemoveCutLine(mLocation.pos) || removed;
bool removed = false;
for (auto channel :
TrackList::Channels(mpTrack.get()))
removed = channel->RemoveCutLine(mLocation.pos) || removed;
if (!removed)
// Nothing happened, make no Undo item

View File

@ -213,14 +213,9 @@ void WaveColorMenuTable::OnWaveColorChange(wxCommandEvent & event)
int newWaveColor = id - OnInstrument1ID;
AudacityProject *const project = ::GetActiveProject();
// TrackList *const tracks = project->GetTracks();
pTrack->SetWaveColorIndex(newWaveColor);
// Assume partner is wave or null
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
if (partner)
partner->SetWaveColorIndex(newWaveColor);
for (auto channel : TrackList::Channels(pTrack))
channel->SetWaveColorIndex(newWaveColor);
project->PushState(wxString::Format(_("Changed '%s' to %s"),
pTrack->GetName(),
@ -336,12 +331,9 @@ void FormatMenuTable::OnFormatChange(wxCommandEvent & event)
return; // Nothing to do.
AudacityProject *const project = ::GetActiveProject();
pTrack->ConvertToSampleFormat(newFormat);
// Assume partner is wave or null
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
if (partner)
partner->ConvertToSampleFormat(newFormat);
for (auto channel : TrackList::Channels(pTrack))
channel->ConvertToSampleFormat(newFormat);
/* i18n-hint: The strings name a track and a format */
project->PushState(wxString::Format(_("Changed '%s' to %s"),
@ -439,11 +431,9 @@ int RateMenuTable::IdOfRate(int rate)
void RateMenuTable::SetRate(WaveTrack * pTrack, double rate)
{
AudacityProject *const project = ::GetActiveProject();
pTrack->SetRate(rate);
// Assume linked track is wave or null
const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
if (partner)
partner->SetRate(rate);
for (auto channel : TrackList::Channels(pTrack))
channel->SetRate(rate);
// Separate conversion of "rate" enables changing the decimals without affecting i18n
wxString rateString = wxString::Format(wxT("%.3f"), rate);
/* i18n-hint: The string names a track */
@ -733,22 +723,13 @@ void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event)
(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));
for (auto channel : TrackList::Channels(pTrack)) {
channel->SetLastScaleType();
channel->SetDisplay(WaveTrack::WaveTrackDisplay(id));
if (wrongScale)
partner->GetIndependentWaveformSettings().scaleType = linear
? WaveformSettings::stLinear
: WaveformSettings::stLogarithmic;
channel->GetIndependentWaveformSettings().scaleType = linear
? WaveformSettings::stLinear
: WaveformSettings::stLogarithmic;
}
AudacityProject *const project = ::GetActiveProject();

View File

@ -47,12 +47,9 @@ UIHandle::Result GainSliderHandle::SetValue
auto pTrack = GetWaveTrack();
if (pTrack) {
pTrack->SetGain(newValue);
// Assume linked track is wave or null
const auto link = static_cast<WaveTrack*>(mpTrack.lock()->GetLink());
if (link)
link->SetGain(newValue);
for (auto channel :
TrackList::Channels(pTrack.get()))
channel->SetGain(newValue);
MixerBoard *const pMixerBoard = pProject->GetMixerBoard();
if (pMixerBoard)
@ -131,12 +128,9 @@ UIHandle::Result PanSliderHandle::SetValue(AudacityProject *pProject, float newV
auto pTrack = GetWaveTrack();
if (pTrack) {
pTrack->SetPan(newValue);
// Assume linked track is wave or null
const auto link = static_cast<WaveTrack*>(pTrack->GetLink());
if (link)
link->SetPan(newValue);
for (auto channel :
TrackList::Channels(pTrack.get()))
channel->SetPan(newValue);
MixerBoard *const pMixerBoard = pProject->GetMixerBoard();
if (pMixerBoard)

View File

@ -58,13 +58,12 @@ void WaveTrackVRulerControls::DoZoomPreset( int i)
const auto wt = static_cast<WaveTrack*>(pTrack.get());
// Don't pass the partner, that causes problems when updating display
// Don't do all channels, that causes problems when updating display
// during recording and there are special pending tracks.
// This function implements WaveTrack::DoSetMinimized which is always
// called in a context that loops over linked tracks too and reinvokes.
auto partner = nullptr;
WaveTrackVZoomHandle::DoZoom(
NULL, wt, partner, (i==1)?kZoomHalfWave: kZoom1to1,
NULL, wt, false, (i==1)?kZoomHalfWave: kZoom1to1,
wxRect(0,0,0,0), 0,0, true);
}
@ -88,9 +87,7 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
wxASSERT(pTrack->GetKind() == Track::Wave);
auto steps = evt.steps;
const auto wt = static_cast<WaveTrack*>(pTrack.get());
// Assume linked track is wave or null
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
WaveTrack *const wt = static_cast<WaveTrack*>(pTrack.get());
const bool isDB =
wt->GetDisplay() == WaveTrack::Waveform &&
wt->GetWaveformSettings().scaleType == WaveformSettings::stLogarithmic;
@ -102,24 +99,20 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
if (!(min < 0.0 && max > 0.0))
return RefreshNone;
WaveformSettings &settings = wt->GetIndependentWaveformSettings();
WaveformSettings &settings =
wt->GetIndependentWaveformSettings();
float olddBRange = settings.dBRange;
if (steps < 0)
// Zoom out
settings.NextLowerDBRange();
else
settings.NextHigherDBRange();
float newdBRange = settings.dBRange;
if (partner) {
WaveformSettings &settings = partner->GetIndependentWaveformSettings();
for (auto channel : TrackList::Channels(wt)) {
WaveformSettings &channelSettings =
channel->GetIndependentWaveformSettings();
if (steps < 0)
// Zoom out
settings.NextLowerDBRange();
channelSettings.NextLowerDBRange();
else
settings.NextHigherDBRange();
channelSettings.NextHigherDBRange();
}
float newdBRange = settings.dBRange;
// Is y coordinate within the rectangle half-height centered about
// the zero level?
@ -135,19 +128,16 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
const float extreme = (LINEAR_TO_DB(2) + newdBRange) / newdBRange;
max = std::min(extreme, max * olddBRange / newdBRange);
min = std::max(-extreme, min * olddBRange / newdBRange);
wt->SetLastdBRange();
wt->SetDisplayBounds(min, max);
if (partner) {
partner->SetLastdBRange();
partner->SetDisplayBounds(min, max);
for (auto channel : TrackList::Channels(wt)) {
channel->SetLastdBRange();
channel->SetDisplayBounds(min, max);
}
}
}
else if (event.CmdDown() && !event.ShiftDown()) {
const int yy = event.m_y;
const auto partner = static_cast<WaveTrack *>(wt);
WaveTrackVZoomHandle::DoZoom(
pProject, wt, partner, (steps < 0)?kZoomOut:kZoomIn,
pProject, wt, true, (steps < 0)?kZoomOut:kZoomIn,
evt.rect, yy, yy, true);
}
else if (!event.CmdDown() && event.ShiftDown()) {
@ -173,9 +163,8 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
std::min(bound,
numberScale.PositionToValue(numberScale.ValueToPosition(newBottom) + 1.0f));
wt->SetSpectrumBounds(newBottom, newTop);
if (partner)
partner->SetSpectrumBounds(newBottom, newTop);
for (auto channel : TrackList::Channels(wt))
channel->SetSpectrumBounds(newBottom, newTop);
}
else {
float topLimit = 2.0;
@ -191,9 +180,8 @@ unsigned WaveTrackVRulerControls::HandleWheelRotation
float newTop = std::min(topLimit, top + delta);
const float newBottom = std::max(bottomLimit, newTop - range);
newTop = std::min(topLimit, newBottom + range);
wt->SetDisplayBounds(newBottom, newTop);
if (partner)
partner->SetDisplayBounds(newBottom, newTop);
for (auto channel : TrackList::Channels(wt))
channel->SetDisplayBounds(newBottom, newTop);
}
}
else

View File

@ -65,11 +65,12 @@ void WaveTrackVZoomHandle::Enter(bool)
// the zoomKind and cause a drag-zoom-in.
void WaveTrackVZoomHandle::DoZoom
(AudacityProject *pProject,
WaveTrack *pTrack, WaveTrack *partner, int ZoomKind,
WaveTrack *pTrack, bool allChannels, int ZoomKind,
const wxRect &rect, int zoomStart, int zoomEnd,
bool fixedMousePoint)
{
static const float ZOOMLIMIT = 0.001f;
int height = rect.height;
int ypos = rect.y;
@ -318,15 +319,13 @@ void WaveTrackVZoomHandle::DoZoom
}
// Now actually apply the zoom.
if (spectral) {
pTrack->SetSpectrumBounds(min, max);
if (partner)
partner->SetSpectrumBounds(min, max);
}
else {
pTrack->SetDisplayBounds(min, max);
if (partner)
partner->SetDisplayBounds(min, max);
for (auto channel : TrackList::Channels(pTrack)) {
if (!allChannels && channel != pTrack)
continue;
if (spectral)
channel->SetSpectrumBounds(min, max);
else
channel->SetDisplayBounds(min, max);
}
zoomEnd = zoomStart = 0;
@ -389,10 +388,8 @@ void WaveTrackVRulerMenuTable::InitMenu(Menu *, void *pUserData)
void WaveTrackVRulerMenuTable::OnZoom( int iZoomCode )
{
// Assume linked track is wave or null
const auto partner = static_cast<WaveTrack *>(mpData->pTrack->GetLink());
WaveTrackVZoomHandle::DoZoom
(::GetActiveProject(), mpData->pTrack, partner,
(::GetActiveProject(), mpData->pTrack, true,
iZoomCode, mpData->rect, mpData->yy, mpData->yy, false);
using namespace RefreshCode;
@ -467,17 +464,17 @@ void WaveformVRulerMenuTable::OnWaveformScaleType(wxCommandEvent &evt)
{
WaveTrack *const wt = mpData->pTrack;
// Assume linked track is wave or null
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
const WaveformSettings::ScaleType newScaleType =
WaveformSettings::ScaleType(
std::max(0,
std::min((int)(WaveformSettings::stNumScaleTypes) - 1,
evt.GetId() - OnFirstWaveformScaleID
)));
if (wt->GetWaveformSettings().scaleType != newScaleType) {
wt->GetIndependentWaveformSettings().scaleType = newScaleType;
if (partner)
partner->GetIndependentWaveformSettings().scaleType = newScaleType;
for (auto channel : TrackList::Channels(wt)) {
channel->GetIndependentWaveformSettings().scaleType = newScaleType;
}
::GetActiveProject()->ModifyState(true);
@ -540,8 +537,7 @@ END_POPUP_MENU()
void SpectrumVRulerMenuTable::OnSpectrumScaleType(wxCommandEvent &evt)
{
WaveTrack *const wt = mpData->pTrack;
// Assume linked track is wave or null
const auto partner = static_cast<WaveTrack*>(wt->GetLink());
const SpectrogramSettings::ScaleType newScaleType =
SpectrogramSettings::ScaleType(
std::max(0,
@ -549,9 +545,8 @@ void SpectrumVRulerMenuTable::OnSpectrumScaleType(wxCommandEvent &evt)
evt.GetId() - OnFirstSpectrumScaleID
)));
if (wt->GetSpectrogramSettings().scaleType != newScaleType) {
wt->GetIndependentSpectrogramSettings().scaleType = newScaleType;
if (partner)
partner->GetIndependentSpectrogramSettings().scaleType = newScaleType;
for (auto channel : TrackList::Channels(wt))
channel->GetIndependentSpectrogramSettings().scaleType = newScaleType;
::GetActiveProject()->ModifyState(true);
@ -678,8 +673,7 @@ UIHandle::Result WaveTrackVZoomHandle::Release
if( bVZoom ){
if( shiftDown )
mZoomStart=mZoomEnd;
const auto partner = static_cast<WaveTrack *>(pTrack->GetLink());
DoZoom(pProject, pTrack.get(), partner,
DoZoom(pProject, pTrack.get(), true,
shiftDown ? (rightUp ? kZoom1to1 : kZoomOut) : kZoomIn,
mRect, mZoomStart, mZoomEnd, !shiftDown);
}

View File

@ -42,7 +42,7 @@ public:
static void DoZoom
(AudacityProject *pProject,
WaveTrack *pTrack, WaveTrack *partner, int ZoomKind,
WaveTrack *pTrack, bool allChannels, int ZoomKind,
const wxRect &rect, int zoomStart, int zoomEnd,
bool fixedMousePoint);

View File

@ -178,6 +178,8 @@ UIHandle::Result EnvelopeHandle::Click
const ViewInfo &viewInfo = pProject->GetViewInfo();
const auto pTrack = static_cast<Track*>(evt.pCell.get());
mEnvelopeEditors.clear();
unsigned result = Cancelled;
if (pTrack)
result = pTrack->TypeSwitch< decltype(RefreshNone) >(
@ -191,18 +193,21 @@ UIHandle::Result EnvelopeHandle::Click
mLog = !wt->GetWaveformSettings().isLinear();
wt->GetDisplayBounds(&mLower, &mUpper);
mdBRange = wt->GetWaveformSettings().dBRange;
mEnvelopeEditor =
std::make_unique< EnvelopeEditor >( *mEnvelope, true );
mEnvelopeEditorRight.reset();
// Assume linked track is wave or null
auto partner = static_cast<WaveTrack*>(wt->GetLink());
if (partner)
{
auto clickedEnvelope = partner->GetEnvelopeAtX(event.GetX());
if (clickedEnvelope)
mEnvelopeEditorRight =
std::make_unique< EnvelopeEditor >( *clickedEnvelope, true );
auto channels = TrackList::Channels( wt );
for ( auto channel : channels ) {
if (channel == wt)
mEnvelopeEditors.push_back(
std::make_unique< EnvelopeEditor >( *mEnvelope, true ) );
else {
auto e2 = channel->GetEnvelopeAtX(event.GetX());
if (e2)
mEnvelopeEditors.push_back(
std::make_unique< EnvelopeEditor >( *e2, true ) );
else {
// There isn't necessarily an envelope there; no guarantee a
// linked track has the same WaveClip structure...
}
}
}
return RefreshNone;
@ -211,9 +216,9 @@ UIHandle::Result EnvelopeHandle::Click
if (!mEnvelope)
return Cancelled;
GetTimeTrackData( *pProject, *tt, mdBRange, mLog, mLower, mUpper);
mEnvelopeEditor =
std::make_unique< EnvelopeEditor >( *mEnvelope, false );
mEnvelopeEditorRight.reset();
mEnvelopeEditors.push_back(
std::make_unique< EnvelopeEditor >( *mEnvelope, false )
);
return RefreshNone;
},
@ -289,8 +294,7 @@ UIHandle::Result EnvelopeHandle::Release
_("Envelope")
);
mEnvelopeEditor.reset();
mEnvelopeEditorRight.reset();
mEnvelopeEditors.clear();
using namespace RefreshCode;
return needUpdate ? RefreshCell : RefreshNone;
@ -299,8 +303,7 @@ UIHandle::Result EnvelopeHandle::Release
UIHandle::Result EnvelopeHandle::Cancel(AudacityProject *pProject)
{
pProject->RollbackState();
mEnvelopeEditor.reset();
mEnvelopeEditorRight.reset();
mEnvelopeEditors.clear();
return RefreshCode::RefreshCell;
}
@ -313,14 +316,13 @@ bool EnvelopeHandle::ForwardEventToEnvelopes
// AS: I'm not sure why we can't let the Envelope take care of
// redrawing itself. ?
bool needUpdate =
mEnvelopeEditor->MouseEvent(
event, mRect, viewInfo, mLog, mdBRange, mLower, mUpper);
if (mEnvelopeEditorRight)
needUpdate |=
mEnvelopeEditorRight->MouseEvent(
event, mRect, viewInfo, mLog, mdBRange, mLower, mUpper);
bool needUpdate = false;
for (const auto &pEditor : mEnvelopeEditors) {
needUpdate =
pEditor->MouseEvent(
event, mRect, viewInfo, mLog, mdBRange, mLower, mUpper)
|| needUpdate;
}
return needUpdate;
}

View File

@ -14,6 +14,8 @@ Paul Licameli split from TrackPanel.cpp
#include "../../UIHandle.h"
#include "../../MemoryX.h"
#include <vector>
class wxMouseEvent;
class wxMouseState;
#include <wx/gdicmn.h>
@ -85,8 +87,7 @@ private:
double mdBRange{};
Envelope *mEnvelope{};
std::unique_ptr<EnvelopeEditor> mEnvelopeEditor;
std::unique_ptr<EnvelopeEditor> mEnvelopeEditorRight;
std::vector< std::unique_ptr<EnvelopeEditor> > mEnvelopeEditors;
bool mTimeTrack{};
};

View File

@ -152,6 +152,21 @@ namespace
AddClipsToCaptured( state, t, t->GetStartTime(), t->GetEndTime() );
}
WaveTrack *NthChannel(WaveTrack &leader, int nn)
{
if (nn < 0)
return nullptr;
return *TrackList::Channels( &leader ).begin().advance(nn);
}
int ChannelPosition(const Track *pChannel)
{
return static_cast<int>(
TrackList::Channels( pChannel )
.EndingAfter( pChannel ).size()
) - 1;
}
// Don't count right channels.
WaveTrack *NthAudioTrack(TrackList &list, int nn)
{
@ -206,15 +221,10 @@ namespace
clip.track->Offset( offset );
}
}
else if ( pTrack ) {
else if ( pTrack )
// Was a shift-click
for (auto channel =
pTrack->GetLink() && !pTrack->GetLinked()
? pTrack->GetLink() : pTrack;
channel;
channel = channel->GetLinked() ? channel->GetLink() : nullptr)
for (auto channel : TrackList::Channels( pTrack ))
channel->Offset( offset );
}
}
}
@ -236,16 +246,12 @@ void TimeShiftHandle::CreateListOfCapturedClips
state.capturedClipArray.push_back
(TrackClip( &capturedTrack, state.capturedClip ));
// Check for stereo partner
Track *partner = capturedTrack.GetLink();
WaveTrack *wt;
if (state.capturedClip &&
// Assume linked track is wave or null
nullptr != (wt = static_cast<WaveTrack*>(partner))) {
WaveClip *const clip = FindClipAtTime(wt, clickTime);
if (clip)
state.capturedClipArray.push_back(TrackClip(partner, clip));
if (state.capturedClip) {
// Check for other channels
auto wt = static_cast<WaveTrack*>(&capturedTrack);
for ( auto channel : TrackList::Channels( wt ).Excluding( wt ) )
if (WaveClip *const clip = FindClipAtTime(channel, clickTime))
state.capturedClipArray.push_back(TrackClip(channel, clip));
}
}
@ -493,22 +499,28 @@ namespace {
for ( auto &trackClip : state.capturedClipArray ) {
if (trackClip.clip) {
// Move all clips up or down by an equal count of audio tracks.
// Can only move between tracks with equal numbers of channels,
// and among corresponding channels.
Track *const pSrcTrack = trackClip.track;
auto pDstTrack = NthAudioTrack(trackList,
diff + TrackPosition(trackList, pSrcTrack));
// Can only move mono to mono, or left to left, or right to right
// And that must be so for each captured clip
bool stereo = (pSrcTrack->GetLink() != 0);
if (pDstTrack && stereo && !pSrcTrack->GetLinked())
// Assume linked track is wave or null
pDstTrack = static_cast<WaveTrack*>(pDstTrack->GetLink());
bool ok = pDstTrack &&
(stereo == (pDstTrack->GetLink() != 0)) &&
(!stereo || (pSrcTrack->GetLinked() == pDstTrack->GetLinked()));
if (ok)
trackClip.dstTrack = pDstTrack;
else
if (!pDstTrack)
return false;
if (TrackList::Channels(pSrcTrack).size() !=
TrackList::Channels(pDstTrack).size())
return false;
auto pDstChannel = NthChannel(
*pDstTrack, ChannelPosition(pSrcTrack));
if (!pDstChannel) {
wxASSERT(false);
return false;
}
trackClip.dstTrack = pDstChannel;
}
}
return true;

View File

@ -34,9 +34,9 @@ UIHandle::Result MinimizeButtonHandle::CommitChanges
auto pTrack = mpTrack.lock();
if (pTrack)
{
pTrack->SetMinimized(!pTrack->GetMinimized());
if (pTrack->GetLink())
pTrack->GetLink()->SetMinimized(pTrack->GetMinimized());
bool wasMinimized = pTrack->GetMinimized();
for (auto channel : TrackList::Channels(pTrack.get()))
channel->SetMinimized(!wasMinimized);
pProject->ModifyState(true);
// Redraw all tracks when any one of them expands or contracts

View File

@ -209,11 +209,8 @@ void TrackMenuTable::OnSetName(wxCommandEvent &)
if (bResult)
{
wxString newName = Command.mName;
pTrack->SetName(newName);
// if we have a linked channel this name should change as well
// (otherwise sort by name and time will crash).
if (pTrack->GetLinked())
pTrack->GetLink()->SetName(newName);
for (auto channel : TrackList::Channels(pTrack))
channel->SetName(newName);
MixerBoard *const pMixerBoard = proj->GetMixerBoard();
auto pt = dynamic_cast<PlayableTrack*>(pTrack);