Example #1
0
bool WaveTrack::Paste(double t0, Track *src)
{
   //printf("paste: entering WaveTrack::Paste\n");
   
   if (src->GetKind() != Track::Wave)
      return false;

   //printf("paste: we have a wave track\n");

   WaveTrack* other = (WaveTrack*)src;

   //
   // Pasting is a bit complicated, because with the existence of multiclip mode,
   // we must guess the behaviour the user wants.
   //
   // Currently, two modes are implemented:
   //
   // - If a single clip should be pasted, and it should be pasted inside another
   //   clip, no new clips are generated. The audio is simply inserted.
   //   This resembles the old (pre-multiclip support) behaviour. However, if
   //   the clip is pasted outside of any clip, a new clip is generated. This is
   //   the only behaviour which is different to what was done before, but it
   //   shouldn't confuse users too much.
   //
   // - If multiple clips should be pasted, these are always pasted as single
   //   clips, and the current clip is splitted, when necessary. This may seem
   //   strange at first, but it probably is better than trying to auto-merge
   //   anything. The user can still merge the clips by hand (which should be
   //   a simple command reachable by a hotkey or single mouse click).
   //

   if (other->GetNumClips() == 0)
      return false;

   //printf("paste: we have at least one clip\n");

   double insertDuration = other->GetEndTime();
   WaveClipList::Node* it;

   //printf("Check if we need to make room for the pasted data\n");
   
   // Make room for the pasted data, unless the space being pasted in is empty of
   // any clips
   if (!IsEmpty(t0, t0+insertDuration-1.0/mRate)) {

      for (it=GetClipIterator(); it; it=it->GetNext())
      {
         WaveClip* clip = it->GetData();

         //printf("paste: offsetting already existing clip %i by %f seconds\n",
         //(int)clip, insertDuration);

         if (clip->GetStartTime() > t0-(1.0/mRate))
            clip->Offset(insertDuration);
      }
   }

   if (other->GetNumClips() == 1)
   {
      // Single clip mode
      // printf("paste: checking for single clip mode!\n");
      
      WaveClip *insideClip = NULL;

      for (it=GetClipIterator(); it; it=it->GetNext())
      {
         WaveClip *clip = it->GetData();

         // The 1.0/mRate is the time for one sample - kind of a fudge factor,
         // because an overlap of less than a sample should not trigger
         // traditional behaviour.

         if (t0+src->GetEndTime()-1.0/mRate > clip->GetStartTime() &&
             t0 < clip->GetEndTime() - 1.0/mRate)
         {
            //printf("t0=%.6f: inside clip is %.6f ... %.6f\n",
            //       t0, clip->GetStartTime(), clip->GetEndTime());
            insideClip = clip;
            break;
         }
      }

      if (insideClip)
      {
         // Exhibit traditional behaviour
         //printf("paste: traditional behaviour\n");
         return insideClip->Paste(t0, other->GetClipByIndex(0));
      }

      // Just fall through and exhibit new behaviour
   }

   // Insert new clips
   //printf("paste: multi clip mode!\n");
   
   for (it=other->GetClipIterator(); it; it=it->GetNext())
   {
      WaveClip* clip = it->GetData();

      WaveClip* newClip = new WaveClip(*clip, mDirManager);
      newClip->Offset(t0);
      newClip->MarkChanged();
      mClips.Append(newClip);
   }
   return true;
}
Example #2
0
bool WaveTrack::HandleClear(double t0, double t1,
                            bool addCutLines, bool split)
{
   if (t1 < t0)
      return false;

   WaveClipList::Node* it;
   WaveClipList clipsToDelete;
   WaveClipList clipsToAdd;

   for (it=GetClipIterator(); it; it=it->GetNext())
   {
      WaveClip *clip = it->GetData();

      if (t0 <= clip->GetStartTime() && t1 >= clip->GetEndTime())
      {
         // Whole clip must be deleted - remember this
         clipsToDelete.Append(clip);
      } else
      if (t1 > clip->GetStartTime() && t0 < clip->GetEndTime())
      {
         // Clip data is affected by command
         if (addCutLines)
         {
            if (!clip->ClearAndAddCutLine(t0,t1))
               return false;
         } else
         {
            if (split) {
               // Three cases:

               if (t0 <= clip->GetStartTime()) {
                  // Delete from the left edge
                  clip->Clear(clip->GetStartTime(), t1);
                  clip->Offset(t1-clip->GetStartTime());
               } else
               if (t1 >= clip->GetEndTime()) {
                  // Delete to right edge
                  clip->Clear(t0, clip->GetEndTime());
               } else
               {
                  // Delete in the middle of the clip...we actually create two
                  // new clips out of the left and right halves...

                  WaveClip *left = new WaveClip(*clip, mDirManager);
                  left->Clear(t0, clip->GetEndTime());
                  clipsToAdd.Append(left);

                  WaveClip *right = new WaveClip(*clip, mDirManager);
                  right->Clear(clip->GetStartTime(), t1);
                  right->Offset(t1-clip->GetStartTime());
                  clipsToAdd.Append(right);

                  clipsToDelete.Append(clip);
               }
            }
            else {
               if (!clip->Clear(t0,t1))
                  return false;
            }
         }
      } else
      if (clip->GetStartTime() >= t1)
      {
         // Clip is "behind" the region -- offset it unless we're splitting
         if (!split)
            clip->Offset(-(t1-t0));
      }
   }

   for (it=clipsToDelete.GetFirst(); it; it=it->GetNext())
   {
      mClips.DeleteObject(it->GetData());
      delete it->GetData();
   }

   for (it=clipsToAdd.GetFirst(); it; it=it->GetNext())
   {
      mClips.Append(it->GetData());
   }

   return true;
}
Example #3
0
bool WaveTrack::Copy(double t0, double t1, Track **dest)
{
   *dest = NULL;

   if (t1 <= t0)
      return false;

   WaveTrack *newTrack = new WaveTrack(mDirManager);

   newTrack->Init(*this);

   WaveClipList::Node* it;
   
   for (it=GetClipIterator(); it; it=it->GetNext())
   {
      WaveClip *clip = it->GetData();

      if (t0 <= clip->GetStartTime() && t1 >= clip->GetEndTime())
      {
         // Whole clip is in copy region
         //printf("copy: clip %i is in copy region\n", (int)clip);
         
         WaveClip *newClip = new WaveClip(*clip, mDirManager);
         newClip->RemoveAllCutLines();
         newClip->Offset(-t0);
         newTrack->mClips.Append(newClip);
      } else
      if (t1 > clip->GetStartTime() && t0 < clip->GetEndTime())
      {
         // Clip is affected by command
         //printf("copy: clip %i is affected by command\n", (int)clip);
         
         WaveClip *newClip = new WaveClip(*clip, mDirManager);
         newClip->RemoveAllCutLines();
         double clip_t0 = t0;
         double clip_t1 = t1;
         if (clip_t0 < clip->GetStartTime())
            clip_t0 = clip->GetStartTime();
         if (clip_t1 > clip->GetEndTime())
            clip_t1 = clip->GetEndTime();

         //printf("copy: clip_t0=%f, clip_t1=%f\n", clip_t0, clip_t1);

         newClip->Offset(-t0);
         if (newClip->GetOffset() < 0)
            newClip->SetOffset(0);

         //printf("copy: clip offset is now %f\n", newClip->GetOffset());
            
         if (!newClip->CreateFromCopy(clip_t0, clip_t1, clip))
         {
            //printf("paste: CreateFromCopy(%f, %f, %i) returns false, quitting\n",
            //   clip_t0, clip_t1, (int)clip);

            return false;
         }

         newTrack->mClips.Append(newClip);
      }
   }

   *dest = newTrack;

   return true;
}
Example #4
0
///by default creates the order of the wavetrack to load.
void ODDecodeTask::Update()
{

   std::vector<ODDecodeBlockFile*> tempBlocks;

   mWaveTrackMutex.Lock();

   for(size_t j=0;j<mWaveTracks.size();j++)
   {
      if(mWaveTracks[j])
      {
         WaveClip *clip;
         BlockArray *blocks;
         Sequence *seq;

         //gather all the blockfiles that we should process in the wavetrack.
         WaveClipList::compatibility_iterator node = mWaveTracks[j]->GetClipIterator();

         while(node) {
            clip = node->GetData();
            seq = clip->GetSequence();
            //TODO:this lock is way to big since the whole file is one sequence.  find a way to break it down.
            seq->LockDeleteUpdateMutex();

            //See Sequence::Delete() for why need this for now..
            blocks = clip->GetSequenceBlockArray();
            int i;
            int insertCursor;

            insertCursor =0;//OD TODO:see if this works, removed from inner loop (bfore was n*n)
            for(i=0; i<(int)blocks->GetCount(); i++)
            {
               //since we have more than one ODBlockFile, we will need type flags to cast.
               if(!blocks->Item(i)->f->IsDataAvailable() && ((ODDecodeBlockFile*)blocks->Item(i)->f)->GetDecodeType()==this->GetODType())
               {
                  blocks->Item(i)->f->Ref();
                  ((ODDecodeBlockFile*)blocks->Item(i)->f)->SetStart(blocks->Item(i)->start);
                  ((ODDecodeBlockFile*)blocks->Item(i)->f)->SetClipOffset((sampleCount)(clip->GetStartTime()*clip->GetRate()));

                  //these will always be linear within a sequence-lets take advantage of this by keeping a cursor.
                  while(insertCursor<(int)tempBlocks.size()&&
                     (sampleCount)(tempBlocks[insertCursor]->GetStart()+tempBlocks[insertCursor]->GetClipOffset()) <
                        (sampleCount)(((ODDecodeBlockFile*)blocks->Item(i)->f)->GetStart()+((ODDecodeBlockFile*)blocks->Item(i)->f)->GetClipOffset()))
                     insertCursor++;

                  tempBlocks.insert(tempBlocks.begin()+insertCursor++,(ODDecodeBlockFile*)blocks->Item(i)->f);
               }
            }

            seq->UnlockDeleteUpdateMutex();
            node = node->GetNext();
         }
      }
   }
   mWaveTrackMutex.Unlock();

   //get the new order.
   OrderBlockFiles(tempBlocks);
}
///creates the order of the wavetrack to load.
///by default left to right, or frome the point the user has clicked.
void ODComputeSummaryTask::Update()
{
   std::vector<ODPCMAliasBlockFile*> tempBlocks;

   mWaveTrackMutex.Lock();

   for(size_t j=0;j<mWaveTracks.size();j++)
   {
      if(mWaveTracks[j])
      {
         WaveClip *clip;
         BlockArray *blocks;
         Sequence *seq;

         //gather all the blockfiles that we should process in the wavetrack.
         WaveClipList::compatibility_iterator node = mWaveTracks[j]->GetClipIterator();

         while(node) {
            clip = node->GetData();
            seq = clip->GetSequence();
            //This lock may be way too big since the whole file is one sequence.
            //TODO: test for large files and find a way to break it down.
            Sequence::DeleteUpdateMutexLocker locker(*seq);

            //See Sequence::Delete() for why need this for now..
            //We don't need the mBlockFilesMutex here because it is only for the vector list.
            //These are existing blocks, and its wavetrack or blockfiles won't be deleted because
            //of the respective mWaveTrackMutex lock and LockDeleteUpdateMutex() call.
            blocks = clip->GetSequenceBlockArray();
            int i;
            int insertCursor;

            insertCursor =0;//OD TODO:see if this works, removed from inner loop (bfore was n*n)

            for(i=0; i<(int)blocks->size(); i++)
            {
               //if there is data but no summary, this blockfile needs summarizing.
               SeqBlock &block = (*blocks)[i];
               BlockFile *const file = block.f;
               if(file->IsDataAvailable() && !file->IsSummaryAvailable())
               {
                  file->Ref();
                  ODPCMAliasBlockFile *const odpcmaFile = static_cast<ODPCMAliasBlockFile*>(file);
                  odpcmaFile->SetStart(block.start);
                  odpcmaFile->SetClipOffset((sampleCount)(clip->GetStartTime()*clip->GetRate()));

                  //these will always be linear within a sequence-lets take advantage of this by keeping a cursor.
                  while(insertCursor<(int)tempBlocks.size()&&
                     (sampleCount)(tempBlocks[insertCursor]->GetStart()+tempBlocks[insertCursor]->GetClipOffset()) <
                        (sampleCount)(odpcmaFile->GetStart()+odpcmaFile->GetClipOffset()))
                     insertCursor++;

                  tempBlocks.insert(tempBlocks.begin() + insertCursor++, odpcmaFile);
               }
            }
            node = node->GetNext();
         }
      }
   }
   mWaveTrackMutex.Unlock();

   //get the NEW order.
   mBlockFilesMutex.Lock();
   OrderBlockFiles(tempBlocks);
   mBlockFilesMutex.Unlock();

   MarkUpdateRan();
}
Example #6
0
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->Index(track) != wxNOT_FOUND)
      {
         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)
      {
         WaveTrack *waveTrack = (WaveTrack *)track;
         WaveClipList::compatibility_iterator it;
         for (it = waveTrack->GetClipIterator(); it; it = it->GetNext())
         {
            WaveClip *clip = it->GetData();
            if (mClipExclusions)
            {
               bool skip = false;
               for (size_t j = 0, cnt = mClipExclusions->GetCount(); j < cnt; ++j)
               {
                  if (mClipExclusions->Item(j).track == waveTrack &&
                      mClipExclusions->Item(j).clip == clip)
                  {
                     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());
}
Example #7
0
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();
   }
}