float ContrastDialog::GetDB() { // not good // why not? // what if more than one track? float rms = float(0.0); AudacityProject *p = GetActiveProject(); TrackListIterator iter(p->GetTracks()); Track *t = iter.First(); if(mT0 > mT1) { wxMessageDialog m(NULL, _("Start time after after end time!\nPlease enter reasonable times."), _("Error"), wxOK); m.ShowModal(); return 1234.0; // 'magic number', but the whole +ve dB range will 'almost' never occur } if(mT0 < t->GetStartTime()) mT0 = t->GetStartTime(); if(mT1 > t->GetEndTime()) mT1 = t->GetEndTime(); if(mT0 > mT1) { wxMessageDialog m(NULL, _("Times are not reasonable!\nPlease enter reasonable times."), _("Error"), wxOK); m.ShowModal(); return 1234.0; } if(mT0 == mT1) return 1234.0; while(t) { // this isn't quite right. What to do if more than one track selected? ((WaveTrack *)t)->GetRMS(&rms, mT0, mT1); t = iter.Next(); } return 20.0*log10(rms); }
double TrackList::GetStartTime() const { if (IsEmpty()) return 0.0; double min = head->t->GetStartTime(); // head->t should be APIfied ConstTrackListIterator iter(this); for (Track *t = iter.First(); t; t = iter.Next()) { double l = t->GetStartTime(); if (l < min) min = l; } return min; }
void SnapManager::Reinit() { int snapTo = mProject->GetSnapTo(); double rate = mProject->GetRate(); wxString format = mProject->GetSelectionFormat(); // No need to reinit if these are still the same if (snapTo == mSnapTo && rate == mRate && format == mFormat) { return; } // Save NEW settings mSnapTo = snapTo; mRate = rate; mFormat = format; mSnapPoints.clear(); // Grab time-snapping prefs (unless otherwise requested) mSnapToTime = false; // Look up the format string if (mSnapTo != SNAP_OFF && !mNoTimeSnap) { mSnapToTime = true; mConverter.SetSampleRate(mRate); mConverter.SetFormatName(mFormat); } // Add a SnapPoint at t=0 mSnapPoints.push_back(SnapPoint{}); TrackListIterator iter(mTracks); for (Track *track = iter.First(); track; track = iter.Next()) { if (mTrackExclusions && mTrackExclusions->end() != std::find(mTrackExclusions->begin(), mTrackExclusions->end(), track)) { continue; } if (track->GetKind() == Track::Label) { LabelTrack *labelTrack = (LabelTrack *)track; for (int i = 0, cnt = labelTrack->GetNumLabels(); i < cnt; ++i) { const LabelStruct *label = labelTrack->GetLabel(i); const double t0 = label->getT0(); const double t1 = label->getT1(); CondListAdd(t0, labelTrack); if (t1 != t0) { CondListAdd(t1, labelTrack); } } } else if (track->GetKind() == Track::Wave) { auto waveTrack = static_cast<const WaveTrack *>(track); for (const auto &clip: waveTrack->GetClips()) { if (mClipExclusions) { bool skip = false; for (size_t j = 0, cnt = mClipExclusions->size(); j < cnt; ++j) { if ((*mClipExclusions)[j].track == waveTrack && (*mClipExclusions)[j].clip == clip.get()) { skip = true; break; } } if (skip) { continue; } } CondListAdd(clip->GetStartTime(), waveTrack); CondListAdd(clip->GetEndTime(), waveTrack); } } #ifdef USE_MIDI else if (track->GetKind() == Track::Note) { CondListAdd(track->GetStartTime(), track); CondListAdd(track->GetEndTime(), track); } #endif } // Sort all by time std::sort(mSnapPoints.begin(), mSnapPoints.end()); }
bool GetTrackInfoCommand::Apply(CommandExecutionContext context) { wxString mode = GetString(wxT("Type")); long trackIndex = GetLong(wxT("TrackIndex")); // Get the track indicated by the TrackIndex parameter // (Note: this ought to be somewhere else) long i = 0; TrackListIterator iter(context.proj->GetTracks()); Track *t = iter.First(); while (t && i != trackIndex) { t = iter.Next(); ++i; } if (i != trackIndex || !t) { Error(wxT("TrackIndex was invalid.")); return false; } // Now get the particular desired item about the track of interest if (mode.IsSameAs(wxT("Name"))) { Status(t->GetName()); } else if (mode.IsSameAs(wxT("StartTime"))) { Status(wxString::Format(wxT("%f"), t->GetStartTime())); } else if (mode.IsSameAs(wxT("EndTime"))) { Status(wxString::Format(wxT("%f"), t->GetEndTime())); } else if (mode.IsSameAs(wxT("Pan"))) { if(t->GetKind() == Track::Wave) Status(wxString::Format(wxT("%f"), static_cast<WaveTrack*>(t)->GetPan())); } else if (mode.IsSameAs(wxT("Gain"))) { if(t->GetKind() == Track::Wave) Status(wxString::Format(wxT("%f"), static_cast<WaveTrack*>(t)->GetGain())); } else if (mode.IsSameAs(wxT("Focused"))) { TrackPanel *panel = context.proj->GetTrackPanel(); SendBooleanStatus(panel->GetFocusedTrack() == t); } else if (mode.IsSameAs(wxT("Selected"))) { SendBooleanStatus(t->GetSelected()); } else if (mode.IsSameAs(wxT("Linked"))) { SendBooleanStatus(t->GetLinked()); } else if (mode.IsSameAs(wxT("Solo"))) { if (t->GetKind() == Track::Wave) SendBooleanStatus(t->GetSolo()); else SendBooleanStatus(false); } else if (mode.IsSameAs(wxT("Mute"))) { if (t->GetKind() == Track::Wave) SendBooleanStatus(t->GetMute()); else SendBooleanStatus(false); } else { Error(wxT("Invalid info type!")); return false; } return true; }
//TODO-MB: wouldn't it make more sense to DELETE the time track after 'mix and render'? void MixAndRender(TrackList *tracks, TrackFactory *trackFactory, double rate, sampleFormat format, double startTime, double endTime, WaveTrack::Holder &uLeft, WaveTrack::Holder &uRight) { uLeft.reset(), uRight.reset(); // This function was formerly known as "Quick Mix". Track *t; bool mono = false; /* flag if output can be mono without loosing anything*/ bool oneinput = false; /* flag set to true if there is only one input track (mono or stereo) */ TrackListIterator iter(tracks); SelectedTrackListOfKindIterator usefulIter(Track::Wave, tracks); // this only iterates tracks which are relevant to this function, i.e. // selected WaveTracks. The tracklist is (confusingly) the list of all // tracks in the project int numWaves = 0; /* number of wave tracks in the selection */ int numMono = 0; /* number of mono, centre-panned wave tracks in selection*/ t = iter.First(); while (t) { if (t->GetSelected() && t->GetKind() == Track::Wave) { numWaves++; float pan = ((WaveTrack*)t)->GetPan(); if (t->GetChannel() == Track::MonoChannel && pan == 0) numMono++; } t = iter.Next(); } if (numMono == numWaves) mono = true; /* the next loop will do two things at once: * 1. build an array of all the wave tracks were are trying to process * 2. determine when the set of WaveTracks starts and ends, in case we * need to work out for ourselves when to start and stop rendering. */ double mixStartTime = 0.0; /* start time of first track to start */ bool gotstart = false; // flag indicates we have found a start time double mixEndTime = 0.0; /* end time of last track to end */ double tstart, tend; // start and end times for one track. WaveTrackConstArray waveArray; t = iter.First(); while (t) { if (t->GetSelected() && t->GetKind() == Track::Wave) { waveArray.push_back(static_cast<WaveTrack *>(t)); tstart = t->GetStartTime(); tend = t->GetEndTime(); if (tend > mixEndTime) mixEndTime = tend; // try and get the start time. If the track is empty we will get 0, // which is ambiguous because it could just mean the track starts at // the beginning of the project, as well as empty track. The give-away // is that an empty track also ends at zero. if (tstart != tend) { // we don't get empty tracks here if (!gotstart) { // no previous start, use this one unconditionally mixStartTime = tstart; gotstart = true; } else if (tstart < mixStartTime) mixStartTime = tstart; // have a start, only make it smaller } // end if start and end are different } // end if track is a selected WaveTrack. /** @TODO: could we not use a SelectedTrackListOfKindIterator here? */ t = iter.Next(); } /* create the destination track (NEW track) */ if ((numWaves == 1) || ((numWaves == 2) && (usefulIter.First()->GetLink() != NULL))) oneinput = true; // only one input track (either 1 mono or one linked stereo pair) auto mixLeft = trackFactory->NewWaveTrack(format, rate); if (oneinput) mixLeft->SetName(usefulIter.First()->GetName()); /* set name of output track to be the same as the sole input track */ else mixLeft->SetName(_("Mix")); mixLeft->SetOffset(mixStartTime); decltype(mixLeft) mixRight{}; if (mono) { mixLeft->SetChannel(Track::MonoChannel); } else { mixRight = trackFactory->NewWaveTrack(format, rate); if (oneinput) { if (usefulIter.First()->GetLink() != NULL) // we have linked track mixLeft->SetName(usefulIter.First()->GetLink()->GetName()); /* set name to match input track's right channel!*/ else mixLeft->SetName(usefulIter.First()->GetName()); /* set name to that of sole input channel */ } else mixRight->SetName(_("Mix")); mixLeft->SetChannel(Track::LeftChannel); mixRight->SetChannel(Track::RightChannel); mixRight->SetOffset(mixStartTime); mixLeft->SetLinked(true); } int maxBlockLen = mixLeft->GetIdealBlockSize(); // If the caller didn't specify a time range, use the whole range in which // any input track had clips in it. if (startTime == endTime) { startTime = mixStartTime; endTime = mixEndTime; } Mixer mixer(waveArray, Mixer::WarpOptions(tracks->GetTimeTrack()), startTime, endTime, mono ? 1 : 2, maxBlockLen, false, rate, format); ::wxSafeYield(); int updateResult = eProgressSuccess; { ProgressDialog progress(_("Mix and Render"), _("Mixing and rendering tracks")); while (updateResult == eProgressSuccess) { sampleCount blockLen = mixer.Process(maxBlockLen); if (blockLen == 0) break; if (mono) { samplePtr buffer = mixer.GetBuffer(); mixLeft->Append(buffer, format, blockLen); } else { samplePtr buffer; buffer = mixer.GetBuffer(0); mixLeft->Append(buffer, format, blockLen); buffer = mixer.GetBuffer(1); mixRight->Append(buffer, format, blockLen); } updateResult = progress.Update(mixer.MixGetCurrentTime() - startTime, endTime - startTime); } } mixLeft->Flush(); if (!mono) mixRight->Flush(); if (updateResult == eProgressCancelled || updateResult == eProgressFailed) { return; } else { uLeft = std::move(mixLeft), uRight = std::move(mixRight); #if 0 int elapsedMS = wxGetElapsedTime(); double elapsedTime = elapsedMS * 0.001; double maxTracks = totalTime / (elapsedTime / numWaves); // Note: these shouldn't be translated - they're for debugging // and profiling only. printf(" Tracks: %d\n", numWaves); printf(" Mix length: %f sec\n", totalTime); printf("Elapsed time: %f sec\n", elapsedTime); printf("Max number of tracks to mix in real time: %f\n", maxTracks); #endif } }
float ContrastDialog::GetDB() { // FIXME: what if more than one track? float rms = float(0.0); AudacityProject *p = GetActiveProject(); TrackListOfKindIterator iter(Track::Wave, p->GetTracks()); Track *t = iter.First(); if(mT0 > mT1) { wxMessageDialog m(NULL, _("Start time after end time!\nPlease enter reasonable times."), _("Error"), wxOK); m.ShowModal(); return 1234.0; // 'magic number', but the whole +ve dB range will 'almost' never occur } if(mT0 < t->GetStartTime()) mT0 = t->GetStartTime(); if(mT1 > t->GetEndTime()) mT1 = t->GetEndTime(); if(mT0 > mT1) { wxMessageDialog m(NULL, _("Times are not reasonable!\nPlease enter reasonable times."), _("Error"), wxOK); m.ShowModal(); return 1234.0; } if(mT0 == mT1) { wxMessageDialog m(NULL, _("Nothing to measure.\nPlease select a section of a track."), _("Error"), wxOK); m.ShowModal(); return 1234.0; } bool mSelected = false; while(t) { if( ((WaveTrack *)t)->GetSelected() ) { if( mSelected == true ) // already measured one track { wxMessageDialog m(NULL, _("You can only measure one track at a time."), _("Error"), wxOK); m.ShowModal(); return 1234.0; } else { ((WaveTrack *)t)->GetRMS(&rms, mT0, mT1); mSelected = true; } } t = iter.Next(); } if( mSelected ) { if( rms < 1.0E-30 ) return -60.0; return 20.0*log10(rms); } else { wxMessageDialog m(NULL, _("Please select something to be measured."), _("Error"), wxOK); m.ShowModal(); return 1234.0; } }
double StretchHandle::GetT0(const Track &track, const ViewInfo &viewInfo) { return std::max(track.GetStartTime(), viewInfo.selectedRegion.t0()); }
SnapManager::SnapManager(TrackList *tracks, TrackClipArray *exclusions, double zoom, int pixelTolerance, bool noTimeSnap) { int i; // Grab time-snapping prefs (unless otherwise requested) mSnapToTime = false; AudacityProject *p = GetActiveProject(); wxASSERT(p); if (p) { // Look up the format string if (p->GetSnapTo() && !noTimeSnap) { mSnapToTime = true; mConverter.SetSampleRate(p->GetRate()); mConverter.SetFormatName(p->GetSelectionFormat()); } } mSnapPoints = new SnapPointArray(CompareSnapPoints); if (zoom > 0 && pixelTolerance > 0) mTolerance = pixelTolerance / zoom; else { // This shouldn't happen, but we don't want to crash if we get // illegal values. The net effect of this is to never snap. mTolerance = 0.0; } // Two time points closer than this are considered the same mEpsilon = 1 / 44100.0; // Add a SnapPoint at t=0 mSnapPoints->Add(new SnapPoint(0.0, NULL)); TrackListIterator iter(tracks); Track *track = iter.First(); while (track) { if (track->GetKind() == Track::Label) { LabelTrack *labelTrack = (LabelTrack *)track; for(i = 0; i < labelTrack->GetNumLabels(); i++) { const LabelStruct *label = labelTrack->GetLabel(i); CondListAdd(label->t, labelTrack); if (label->t1 != label->t) { CondListAdd(label->t1, labelTrack); } } } else if (track->GetKind() == Track::Wave) { WaveTrack *waveTrack = (WaveTrack *)track; WaveClipList::compatibility_iterator it; for (it=waveTrack->GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); if (exclusions) { bool skip = false; for(int j=0; j<(int)exclusions->GetCount(); j++) { if ((*exclusions)[j].track == waveTrack && (*exclusions)[j].clip == clip) skip = true; } if (skip) continue; } CondListAdd(clip->GetStartTime(), waveTrack); CondListAdd(clip->GetEndTime(), waveTrack); } } #ifdef USE_MIDI else if (track->GetKind() == Track::Note) { CondListAdd(track->GetStartTime(), track); CondListAdd(track->GetEndTime(), track); } #endif track = iter.Next(); } }