// Labels inside the affected region are moved to match the audio; labels after // it are shifted along appropriately. bool EffectSBSMS::ProcessLabelTrack(Track *t) { TimeWarper *warper = createTimeWarper(mT0,mT1,(mT1-mT0)*mTotalStretch,rateStart,rateEnd,rateSlideType); SetTimeWarper(new RegionTimeWarper(mT0, mT1, warper)); LabelTrack *lt = (LabelTrack*)t; if (lt == NULL) return false; lt->WarpLabels(*GetTimeWarper()); return true; }
// Labels are time-scaled linearly inside the affected region, and labels after // the region are shifted along according to how the region size changed. bool EffectChangeSpeed::ProcessLabelTrack(Track *t) { SetTimeWarper(new RegionTimeWarper(mT0, mT1, new LinearTimeWarper(mT0, mT0, mT1, mT0 + (mT1-mT0)*mFactor))); LabelTrack *lt = (LabelTrack*)t; if (lt == NULL) return false; lt->WarpLabels(*GetTimeWarper()); return true; }
bool EffectSoundTouch::ProcessLabelTrack(Track *track) { // SetTimeWarper(new RegionTimeWarper(mCurT0, mCurT1, // new LinearTimeWarper(mCurT0, mCurT0, // mCurT1, mCurT0 + (mCurT1-mCurT0)*mFactor))); LabelTrack *lt = (LabelTrack*)track; if (lt == NULL) return false; lt->WarpLabels(*GetTimeWarper()); return true; }
bool LabelDialog::TransferDataFromWindow() { int cnt = mData.size(); int i; TrackListIterator iter(mTracks); Track *t; int tndx = 0; // Clear all label tracks of labels for (t = iter.First(); t; t = iter.Next()) { if (t->GetKind() == Track::Label) { LabelTrack *lt = (LabelTrack *)t; tndx++; for (i = lt->GetNumLabels() - 1; i >= 0 ; i--) { lt->DeleteLabel(i); } } } // Create any added tracks while (tndx < (int)mTrackNames.GetCount() - 1) { // Extract the name wxString name = mTrackNames[tndx + 1].AfterFirst(wxT('-')).Mid(1); // Create the NEW track and add to track list auto newTrack = mFactory.NewLabelTrack(); newTrack->SetName(name); mTracks->Add(std::move(newTrack)); tndx++; } // Repopulate with updated labels for (i = 0; i < cnt; i++) { RowData &rd = mData[i]; // Look for track with matching index tndx = 1; for (t = iter.First(); t; t = iter.Next()) { if (t->GetKind() == Track::Label && rd.index == tndx++) { break; } } wxASSERT(t); if (!t) return false; // Add the label to it ((LabelTrack *) t)->AddLabel(rd.selectedRegion, rd.title); ((LabelTrack *) t)->Unselect(); } return true; }
bool LabelDialog::TransferDataFromWindow() { int cnt = mData.GetCount(); int i; TrackListIterator iter(mTracks); Track *t; int tndx = 0; // Clear all label tracks of labels for (t = iter.First(); t; t = iter.Next()) { if (t->GetKind() == Track::Label) { LabelTrack *lt = (LabelTrack *)t; tndx++; for (i = lt->GetNumLabels() - 1; i >= 0 ; i--) { lt->DeleteLabel(i); } } } // Create any added tracks while (tndx < (int)mTrackNames.GetCount() - 1) { // Extract the name wxString name = mTrackNames[tndx + 1].AfterFirst(wxT('-')).Mid(1); // Create the new track and add to track list LabelTrack *newTrack = new LabelTrack(mDirManager); newTrack->SetName(name); mTracks->Add(newTrack); tndx++; } // Repopulate with updated labels for (i = 0; i < cnt; i++) { RowData *rd = mData[i]; // Look for track with matching index tndx = 1; for (t = iter.First(); t; t = iter.Next()) { if (t->GetKind() == Track::Label && rd->index == tndx++) { break; } } // Add the label to it if (!rd->title.IsEmpty()) { ((LabelTrack *) t)->AddLabel(rd->stime, rd->etime, rd->title); ((LabelTrack *) t)->Unselect(); } } return true; }
void AudacityProject::OnNewLabelTrack(wxCommandEvent & event) { LabelTrack *t = new LabelTrack(&mDirManager); SelectNone(); mTracks->Add(t); t->SetSelected(true); PushState(_("Created new label track")); FixScrollbars(); mTrackPanel->Refresh(false); }
// Labels inside the affected region are moved to match the audio; labels after // it are shifted along appropriately. bool EffectSBSMS::ProcessLabelTrack(Track *t) { TimeWarper *warper = NULL; if (rateStart == rateEnd) { warper = new LinearTimeWarper(mT0, mT0, mT1, mT0+(mT1-mT0)*mTotalStretch); } else { warper = new LogarithmicTimeWarper(mT0, mT1, rateStart, rateEnd); } SetTimeWarper(new RegionTimeWarper(mT0, mT1, warper)); LabelTrack *lt = (LabelTrack*)t; if (lt == NULL) return false; lt->WarpLabels(*GetTimeWarper()); return true; }
void LabelDialog::OnImport(wxCommandEvent & WXUNUSED(event)) { wxString path = gPrefs->Read(wxT("/DefaultOpenPath"),::wxGetCwd()); // Ask user for a filename wxString fileName = FileSelector(_("Select a text file containing labels..."), path, // Path wxT(""), // Name wxT(".txt"), // Extension _("Text files (*.txt)|*.txt|All files|*"), wxRESIZE_BORDER, // Flags this); // Parent // They gave us one... if (fileName != wxT("")) { path =::wxPathOnly(fileName); gPrefs->Write(wxT("/DefaultOpenPath"), path); gPrefs->Flush(); wxTextFile f; // Get at the data f.Open(fileName); if (!f.IsOpened()) { wxMessageBox(_("Could not open file: ") + fileName); } else { // Create a temporary label track and load the labels // into it LabelTrack *lt = new LabelTrack(mDirManager); lt->Import(f); // Add the labesls to our collection AddLabels(lt); // Done with the temporary track delete lt; } // Repopulate the grid TransferDataToWindow(); } }
void AudacityProject::OnImportLabels(wxCommandEvent & event) { wxString path = gPrefs->Read("/DefaultOpenPath",::wxGetCwd()); wxString fileName = wxFileSelector(_("Select a text file containing labels..."), path, // Path "", // Name ".txt", // Extension _("Text files (*.txt)|*.txt|" "All files (*.*)|*.*"), 0, // Flags this); // Parent if (fileName != "") { path =::wxPathOnly(fileName); gPrefs->Write("/DefaultOpenPath", path); wxTextFile f; f.Open(fileName); if (!f.IsOpened()) { wxMessageBox(_("Could not open file: ") + fileName); return; } LabelTrack *newTrack = new LabelTrack(&mDirManager); newTrack->Import(f); SelectNone(); mTracks->Add(newTrack); newTrack->SetSelected(true); PushState(wxString:: Format(_("Imported labels from '%s'"), fileName.c_str())); FixScrollbars(); mTrackPanel->Refresh(false); } }
bool EffectReverse::Process() { //Track::All is needed because Reverse should move the labels too this->CopyInputTracks(Track::All); // Set up mOutputTracks. bool bGoodResult = true; TrackListIterator iter(mOutputTracks); Track *t = iter.First(); int count = 0; while (t) { if (t->GetKind() == Track::Wave && (t->GetSelected() || t->IsSyncLockSelected())) { WaveTrack *track = (WaveTrack*)t; if (mT1 > mT0) { sampleCount start = track->TimeToLongSamples(mT0); sampleCount end = track->TimeToLongSamples(mT1); sampleCount len = (sampleCount)(end - start); if (!ProcessOneWave(count, track, start, len)) { bGoodResult = false; break; } } } else if (t->GetKind() == Track::Label && (t->GetSelected() || t->IsSyncLockSelected())) { LabelTrack *track = (LabelTrack*)t; track->ChangeLabelsOnReverse(mT0, mT1); } t = iter.Next(); count++; } this->ReplaceProcessedTracks(bGoodResult); return bGoodResult; }
bool EffectFindClipping::Process() { LabelTrack *l = NULL; Track *original = NULL; TrackListOfKindIterator iter(Track::Label, mTracks); for (Track *t = iter.First(); t; t = iter.Next()) { if (t->GetName() == wxT("Clipping")) { l = (LabelTrack *) t; // copy LabelTrack here, so it can be undone on cancel l->Copy(l->GetStartTime(), l->GetEndTime(), &original); original->SetOffset(l->GetStartTime()); original->SetName(wxT("Clipping")); break; } } if (!l) { l = mFactory->NewLabelTrack(); l->SetName(_("Clipping")); mTracks->Add((Track *) l); } int count = 0; // JC: Only process selected tracks. SelectedTrackListOfKindIterator waves(Track::Wave, mTracks); WaveTrack *t = (WaveTrack *) waves.First(); while (t) { double trackStart = t->GetStartTime(); double trackEnd = t->GetEndTime(); double t0 = mT0 < trackStart ? trackStart : mT0; double t1 = mT1 > trackEnd ? trackEnd : mT1; if (t1 > t0) { sampleCount start = t->TimeToLongSamples(t0); sampleCount end = t->TimeToLongSamples(t1); sampleCount len = (sampleCount)(end - start); if (!ProcessOne(l, count, t, start, len)) { //put it back how it was mTracks->Remove((Track *) l); if(original) { mTracks->Add((Track *) original); } return false; } } count++; t = (WaveTrack *) waves.Next(); } return true; }
bool VampEffect::Process() { if (!mPlugin) return false; TrackListIterator iter(mWaveTracks); int count = 0; WaveTrack *left = (WaveTrack *)iter.First(); bool multiple = false; int prevTrackChannels = 0; TrackListIterator scooter(iter); if (left->GetLinked()) scooter.Next(); if (scooter.Next()) { // if there is another track beyond this one and any linked one, // then we're processing more than one track. That means we // should use the originating track name in each new label // track's name, to make clear which is which multiple = true; } while (left) { sampleCount lstart, rstart; sampleCount len; GetSamples(left, &lstart, &len); WaveTrack *right = NULL; int channels = 1; if (left->GetLinked()) { right = (WaveTrack *)iter.Next(); channels = 2; GetSamples(right, &rstart, &len); } size_t step = mPlugin->getPreferredStepSize(); size_t block = mPlugin->getPreferredBlockSize(); bool initialiseRequired = true; if (block == 0) { if (step != 0) block = step; else block = 1024; } if (step == 0) { step = block; } if (prevTrackChannels > 0) { // Plugin has already been initialised, so if the number of // channels remains the same, we only need to do a reset. // Otherwise we need to re-construct the whole plugin, // because a Vamp plugin can't be re-initialised. if (prevTrackChannels == channels) { mPlugin->reset(); initialiseRequired = false; } else { //!!! todo: retain parameters previously set Init(); } } if (initialiseRequired) { if (!mPlugin->initialise(channels, step, block)) { wxMessageBox(_("Sorry, Vamp Plug-in failed to initialize.")); return false; } } LabelTrack *ltrack = mFactory->NewLabelTrack(); if (!multiple) { ltrack->SetName(GetEffectName()); } else { ltrack->SetName(wxString::Format(wxT("%s: %s"), left->GetName().c_str(), GetEffectName().c_str())); } mTracks->Add(ltrack); float **data = new float*[channels]; for (int c = 0; c < channels; ++c) data[c] = new float[block]; sampleCount originalLen = len; sampleCount ls = lstart; sampleCount rs = rstart; while (len) { int request = block; if (request > len) request = len; if (left) left->Get((samplePtr)data[0], floatSample, ls, request); if (right) right->Get((samplePtr)data[1], floatSample, rs, request); if (request < (int)block) { for (int c = 0; c < channels; ++c) { for (int i = request; i < (int)block; ++i) { data[c][i] = 0.f; } } } Vamp::RealTime timestamp = Vamp::RealTime::frame2RealTime (ls, (int)(mRate + 0.5)); Vamp::Plugin::FeatureSet features = mPlugin->process(data, timestamp); AddFeatures(ltrack, features); if (len > (int)step) len -= step; else len = 0; ls += step; rs += step; if (channels > 1) { if (TrackGroupProgress(count, (ls - lstart) / double(originalLen))) return false; } else { if (TrackProgress(count, (ls - lstart) / double(originalLen))) return false; } } Vamp::Plugin::FeatureSet features = mPlugin->getRemainingFeatures(); AddFeatures(ltrack, features); prevTrackChannels = channels; left = (WaveTrack *)iter.Next(); } return true; }
void LabelDialog::OnExport(wxCommandEvent &event) { int cnt = mData.GetCount(); // Silly user (could just disable the button, but that's a hassle ;-)) if (cnt == 0) { wxMessageBox(_("No labels to export.")); return; } wxString fName; fName = FileSelector(_("Export Labels As:"), NULL, _("labels.txt"), wxT("txt"), wxT("*.txt"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER, this); if (fName == wxT("")) return; // Move existing files out of the way. Otherwise wxTextFile will // append to (rather than replace) the current file. if (wxFileExists(fName)) { #ifdef __WXGTK__ wxString safetyFileName = fName + wxT("~"); #else wxString safetyFileName = fName + wxT(".bak"); #endif if (wxFileExists(safetyFileName)) wxRemoveFile(safetyFileName); wxRename(fName, safetyFileName); } wxTextFile f(fName); #ifdef __WXMAC__ wxFile *temp = new wxFile(); temp->Create(fName); delete temp; #else f.Create(); #endif f.Open(); if (!f.IsOpened()) { wxMessageBox(_("Couldn't write to file: ") + fName); return; } // Transfer our collection to a temporary label track LabelTrack *lt = new LabelTrack(mDirManager); int i; for (i = 0; i < cnt; i++) { RowData *rd = mData[i]; lt->AddLabel(rd->stime, rd->etime, rd->title); } // Export them and clean lt->Export(f); delete lt; #ifdef __WXMAC__ f.Write(wxTextFileType_Mac); #else f.Write(); #endif f.Close(); }
bool EffectNyquist::ProcessOne() { nyx_rval rval; if (GetEffectFlags() & INSERT_EFFECT) { nyx_set_audio_params(mCurTrack[0]->GetRate(), 0); } else { nyx_set_audio_params(mCurTrack[0]->GetRate(), mCurLen); nyx_set_input_audio(StaticGetCallback, (void *)this, mCurNumChannels, mCurLen, mCurTrack[0]->GetRate()); } wxString cmd; if (mDebug) { cmd += wxT("(setf *tracenable* T)\n"); if (mExternal) { cmd += wxT("(setf *breakenable* T)\n"); } } for (unsigned int j = 0; j < mControls.GetCount(); j++) { if (mControls[j].type == NYQ_CTRL_REAL) { // We use Internat::ToString() rather than "%f" here because we // always have to use the dot as decimal separator when giving // numbers to Nyquist, whereas using "%f" will use the user's // decimal separator which may be a comma in some countries. cmd += wxString::Format(wxT("(setf %s %s)\n"), mControls[j].var.c_str(), Internat::ToString(mControls[j].val).c_str()); } else if (mControls[j].type == NYQ_CTRL_INT || mControls[j].type == NYQ_CTRL_CHOICE) { cmd += wxString::Format(wxT("(setf %s %d)\n"), mControls[j].var.c_str(), (int)(mControls[j].val)); } else if (mControls[j].type == NYQ_CTRL_STRING) { wxString str = mControls[j].valStr; str.Replace(wxT("\\"), wxT("\\\\")); str.Replace(wxT("\""), wxT("\\\"")); cmd += wxT("(setf "); // restrict variable names to 7-bit ASCII: cmd += mControls[j].var.c_str(); cmd += wxT(" \""); cmd += str; // unrestricted value will become quoted UTF-8 cmd += wxT("\")\n"); } } if (mIsSal) { wxString str = mCmd; str.Replace(wxT("\\"), wxT("\\\\")); str.Replace(wxT("\""), wxT("\\\"")); // this is tricky: we need SAL to call main so that we can get a // SAL traceback in the event of an error (sal-compile catches the // error and calls sal-error-output), but SAL does not return values. // We will catch the value in a special global aud:result and if no // error occurs, we will grab the value with a LISP expression str += wxT("\nset aud:result = main()\n"); if (mDebug) { // since we're about to evaluate SAL, remove LISP trace enable and // break enable (which stops SAL processing) and turn on SAL stack // trace cmd += wxT("(setf *tracenable* nil)\n"); cmd += wxT("(setf *breakenable* nil)\n"); cmd += wxT("(setf *sal-traceback* t)\n"); } if (mCompiler) { cmd += wxT("(setf *sal-compiler-debug* t)\n"); } cmd += wxT("(setf *sal-call-stack* nil)\n"); // if we do not set this here and an error occurs in main, another // error will be raised when we try to return the value of aud:result // which is unbound cmd += wxT("(setf aud:result nil)\n"); cmd += wxT("(sal-compile-audacity \"") + str + wxT("\" t t nil)\n"); // Capture the value returned by main (saved in aud:result), but // set aud:result to nil so sound results can be evaluated without // retaining audio in memory cmd += wxT("(prog1 aud:result (setf aud:result nil))\n"); } else { cmd += mCmd; } int i; for (i = 0; i < mCurNumChannels; i++) { mCurBuffer[i] = NULL; } rval = nyx_eval_expression(cmd.mb_str(wxConvUTF8)); if (rval == nyx_string) { wxMessageBox(NyquistToWxString(nyx_get_string()), wxT("Nyquist"), wxOK | wxCENTRE, mParent); return true; } if (rval == nyx_double) { wxString str; str.Printf(_("Nyquist returned the value:") + wxString(wxT(" %f")), nyx_get_double()); wxMessageBox(str, wxT("Nyquist"), wxOK | wxCENTRE, mParent); return true; } if (rval == nyx_int) { wxString str; str.Printf(_("Nyquist returned the value:") + wxString(wxT(" %d")), nyx_get_int()); wxMessageBox(str, wxT("Nyquist"), wxOK | wxCENTRE, mParent); return true; } if (rval == nyx_labels) { unsigned int numLabels = nyx_get_num_labels(); unsigned int l; LabelTrack *ltrack = NULL; TrackListIterator iter(mOutputTracks); for (Track *t = iter.First(); t; t = iter.Next()) { if (t->GetKind() == Track::Label) { ltrack = (LabelTrack *)t; break; } } if (!ltrack) { ltrack = mFactory->NewLabelTrack(); this->AddToOutputTracks((Track *)ltrack); } for (l = 0; l < numLabels; l++) { double t0, t1; const char *str; nyx_get_label(l, &t0, &t1, &str); ltrack->AddLabel(t0 + mT0, t1 + mT0, UTF8CTOWX(str)); } return true; } if (rval != nyx_audio) { wxMessageBox(_("Nyquist did not return audio.\n"), wxT("Nyquist"), wxOK | wxCENTRE, mParent); return false; } int outChannels; outChannels = nyx_get_audio_num_channels(); if (outChannels > mCurNumChannels) { wxMessageBox(_("Nyquist returned too many audio channels.\n"), wxT("Nyquist"), wxOK | wxCENTRE, mParent); return false; } double rate = mCurTrack[0]->GetRate(); for (i = 0; i < outChannels; i++) { sampleFormat format = mCurTrack[i]->GetSampleFormat(); if (outChannels == mCurNumChannels) { rate = mCurTrack[i]->GetRate(); } mOutputTrack[i] = mFactory->NewWaveTrack(format, rate); mCurBuffer[i] = NULL; } int success = nyx_get_audio(StaticPutCallback, (void *)this); if (!success) { for(i = 0; i < outChannels; i++) { delete mOutputTrack[i]; mOutputTrack[i] = NULL; } return false; } for (i = 0; i < outChannels; i++) { mOutputTrack[i]->Flush(); if (mCurBuffer[i]) { DeleteSamples(mCurBuffer[i]); } mOutputTime = mOutputTrack[i]->GetEndTime(); } for (i = 0; i < mCurNumChannels; i++) { WaveTrack *out; if (outChannels == mCurNumChannels) { out = mOutputTrack[i]; } else { out = mOutputTrack[0]; } mCurTrack[i]->ClearAndPaste(mT0, mT1, out, false, false); // If we were first in the group adjust non-selected group tracks if (mFirstInGroup) { SyncLockedTracksIterator git(mOutputTracks); Track *t; for (t = git.First(mCurTrack[i]); t; t = git.Next()) { if (!t->GetSelected() && t->IsSyncLockSelected()) { t->SyncLockAdjust(mT1, mT0 + out->GetEndTime()); } } } // Only the first channel can be first in its group mFirstInGroup = false; } for (i = 0; i < outChannels; i++) { delete mOutputTrack[i]; mOutputTrack[i] = NULL; } return true; }
void AudacityProject::OnSplitLabels(wxEvent & event) { TrackListIterator iter(mTracks); VTrack *n = iter.First(); VTrack *srcRight = 0; VTrack *srcLeft = 0; bool stereo = false; LabelTrack *label = 0; while(n) { if(n->GetSelected()) { if(n->GetKind() == VTrack::Wave) { if(n->GetLinked() == true) { stereo = true; srcLeft = n; srcRight = iter.Next(); } else { srcRight = n; stereo = false; } } else if(n->GetKind() == VTrack::Label) label = (LabelTrack*)n; // cast necessary to call LabelTrack specific methods } n = iter.Next(); } // one new track for every label, from that label to the next TrackList newTracks; for(int i = 0; i < label->GetNumLabels(); i++) { wxString name = label->GetLabel(i)->title; double begin = label->GetLabel(i)->t; double end; // if on the last label, extend to the end of the wavetrack if(i == label->GetNumLabels() - 1) { if(stereo) end = wxMax(srcLeft->GetMaxLen(), srcRight->GetMaxLen()); else end = srcLeft->GetMaxLen(); } else end = label->GetLabel(i+1)->t; VTrack *destLeft = 0; VTrack *destRight = 0; srcLeft->Copy(begin, end, &destLeft); if (destLeft) { destLeft->Init(*srcLeft); destLeft->SetOffset(wxMax(begin, srcLeft->GetOffset())); destLeft->SetName(name); mTracks->Add(destLeft); } if(stereo) { srcRight->Copy(begin, end, &destRight); if (destRight) { destRight->Init(*srcRight); destRight->SetOffset(wxMax(begin, srcRight->GetOffset())); destRight->SetName(name); mTracks->Add(destRight); } else if(destLeft) // account for possibility of a non-aligned linked track, which could // cause the left channel to be eligible for creating a new track, // but not the right. destLeft->SetLinked(false); } } PushState(_("Split at labels")); FixScrollbars(); mTrackPanel->Refresh(false); }
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(); } }
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{}); TrackListConstIterator iter(mTracks); for (const 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 EffectRepeat::Process() { // Set up mOutputTracks. // This effect needs Track::All for sync-lock grouping. CopyInputTracks(Track::All); int nTrack = 0; bool bGoodResult = true; double maxDestLen = 0.0; // used to change selection to generated bit TrackListIterator iter(mOutputTracks); for (Track *t = iter.First(); t && bGoodResult; t = iter.Next()) { if (t->GetKind() == Track::Label) { if (t->GetSelected() || t->IsSyncLockSelected()) { LabelTrack* track = (LabelTrack*)t; if (!track->Repeat(mT0, mT1, repeatCount)) { bGoodResult = false; break; } } } else if (t->GetKind() == Track::Wave && t->GetSelected()) { WaveTrack* track = (WaveTrack*)t; sampleCount start = track->TimeToLongSamples(mT0); sampleCount end = track->TimeToLongSamples(mT1); sampleCount len = (sampleCount)(end - start); double tLen = track->LongSamplesToTime(len); double tc = mT0 + tLen; if (len <= 0) { continue; } auto dest = track->Copy(mT0, mT1); for(int j=0; j<repeatCount; j++) { if (!track->Paste(tc, dest.get()) || TrackProgress(nTrack, j / repeatCount)) // TrackProgress returns true on Cancel. { bGoodResult = false; break; } tc += tLen; } if (tc > maxDestLen) maxDestLen = tc; nTrack++; } else if (t->IsSyncLockSelected()) { t->SyncLockAdjust(mT1, mT1 + (mT1 - mT0) * repeatCount); } } if (bGoodResult) { // Select the NEW bits + original bit mT1 = maxDestLen; } ReplaceProcessedTracks(bGoodResult); return bGoodResult; }