// get the sum of the sizes of all blocks this track list
// references.  However, if a block is referred to multiple
// times it is only counted once.  Return value is in bytes.
wxLongLong UndoManager::CalculateSpaceUsage(int index)
{
   TrackListOfKindIterator iter(Track::Wave);
   WaveTrack *wt;
   WaveClipList::compatibility_iterator it;
   BlockArray *blocks;
   unsigned int i;

   // get a map of all blocks referenced in this TrackList
   std::map<BlockFile*, wxLongLong> cur;

   wt = (WaveTrack *) iter.First(stack[index]->tracks);
   while (wt) {
      for (it = wt->GetClipIterator(); it; it = it->GetNext()) {
         blocks = it->GetData()->GetSequenceBlockArray();
         for (i = 0; i < blocks->GetCount(); i++) 
         {
            BlockFile* pBlockFile = blocks->Item(i)->f;
            if (pBlockFile->GetFileName().FileExists())
               cur[pBlockFile] = pBlockFile->GetSpaceUsage();
         }
      }
      wt = (WaveTrack *) iter.Next();
   }

   if (index > 0) {
      // get a set of all blocks referenced in all prev TrackList
      std::set<BlockFile*> prev;
      while (--index) {
         wt = (WaveTrack *) iter.First(stack[index]->tracks);
         while (wt) {
            for (it = wt->GetClipIterator(); it; it = it->GetNext()) {
               blocks = it->GetData()->GetSequenceBlockArray();
               for (i = 0; i < blocks->GetCount(); i++) {
                  prev.insert(blocks->Item(i)->f);
               }
            }
            wt = (WaveTrack *) iter.Next();
         }
      }

      // remove all blocks in prevBlockFiles from curBlockFiles
      std::set<BlockFile*>::const_iterator prevIter;
      for (prevIter = prev.begin(); prevIter != prev.end(); prevIter++) {
         cur.erase(*prevIter);
      }
   }

   // sum the sizes of the blocks remaining in curBlockFiles;
   wxLongLong bytes = 0;
   std::map<BlockFile*, wxLongLong>::const_iterator curIter;
   for (curIter = cur.begin(); curIter != cur.end(); curIter++) {
      bytes += curIter->second;
   }

   return bytes;
}
Exemple #2
0
// Find out how much additional space was used to execute
// this operation.
//
// Computed by getting a list of all blocks referenced by
// *this* TrackList and removing all blocks referenced by
// any previous TrackList.
wxLongLong TrackList::GetAdditionalSpaceUsage(UndoStack *stack)
{
   TrackListNode *p;
   // get a map of all blocks referenced in this TrackList
   std::map<BlockFile*,wxLongLong> curBlockFiles;
   for (p = head; p; p = p->next) {
      if (p->t->GetKind() == Track::Wave) {
         WaveTrack* track = ((WaveTrack*)p->t);
         for (WaveClipList::Node* it=track->GetClipIterator(); it; it=it->GetNext())
         {
            WaveClip* clip = it->GetData();
            BlockArray *blocks = clip->GetSequenceBlockArray();
            for (unsigned int i = 0; i < blocks->GetCount(); i++)
               curBlockFiles[blocks->Item(i)->f] = blocks->Item(i)->f->GetSpaceUsage();
         }
      }
   }

   // get a set of all blocks referenced in all prev TrackList
   std::set<BlockFile*> prevBlockFiles;
   unsigned int undoStackIdx = 0;
   for (; undoStackIdx < stack->GetCount(); undoStackIdx++) {
      UndoStackElem *stackElem = stack->Item(undoStackIdx);
      if (stackElem->tracks == this)
         break;
      for (p = stackElem->tracks->head; p; p = p->next) {
         if (p->t->GetKind() == Track::Wave) {
            WaveTrack* track = ((WaveTrack*)p->t);
            for (WaveClipList::Node* it=track->GetClipIterator(); it; it=it->GetNext())
            {
               WaveClip* clip = it->GetData();
               BlockArray *blocks = clip->GetSequenceBlockArray();
               for (unsigned int i = 0; i < blocks->GetCount(); i++)
                  prevBlockFiles.insert(blocks->Item(i)->f);
            }         
         }
      }
   }

   // remove all blocks in prevBlockFiles from curBlockFiles
   std::set<BlockFile*>::const_iterator prevIter = prevBlockFiles.begin();
   for (; prevIter != prevBlockFiles.end(); prevIter++)
      curBlockFiles.erase(*prevIter);

   // sum the sizes of the blocks remaining in curBlockFiles;
   std::map<BlockFile*,wxLongLong>::const_iterator curBfIter =
      curBlockFiles.begin();
   wxLongLong bytes = 0;
   for (;curBfIter != curBlockFiles.end(); curBfIter++)
      bytes += curBfIter->second;

   return bytes;
}
Exemple #3
0
// get the sum of the sizes of all blocks this track list
// references.  However, if a block is referred to multiple
// times it is only counted once.  Return value is in bytes
unsigned int TrackList::GetSpaceUsage()
{
   // the map guarantees that I only count each block once
   std::map<BlockFile*,unsigned int> blockFiles;
   for (TrackListNode *p = head; p; p = p->next) {
      if (p->t->GetKind() == Track::Wave) {
         BlockArray *blocks = ((WaveTrack*)p->t)->GetSequence()->GetBlockArray();
         for (unsigned int i = 0; i < blocks->GetCount(); i++)
            blockFiles[blocks->Item(i)->f] = blocks->Item(i)->f->GetSpaceUsage();
      }
   }

   std::map<BlockFile*,unsigned int>::const_iterator bfIter;
   unsigned int bytes = 0;
   for (bfIter = blockFiles.begin(); bfIter != blockFiles.end(); bfIter++)
      bytes += bfIter->second;

   return bytes;
}
///by default creates the order of the wavetrack to load.
void ODComputeSummaryTask::Update()
{

   std::vector<ODPCMAliasBlockFile*> tempBlocks;
   mWaveTrackMutex.Lock();
   if(mWaveTrack)
   {
      WaveClip *clip;
      BlockArray *blocks;
      Sequence *seq;
      
      //gather all the blockfiles that we should process in the wavetrack.
      WaveClipList::Node* node = mWaveTrack->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;
         for(i=0; i<(int)blocks->GetCount(); i++)
         {
            //in the future if we have more than one ODBlockFile, we will need type flags to cast.
            if(!blocks->Item(i)->f->IsSummaryAvailable())
            {
               blocks->Item(i)->f->Ref();
               ((ODPCMAliasBlockFile*)blocks->Item(i)->f)->SetStart(blocks->Item(i)->start);
               tempBlocks.push_back((ODPCMAliasBlockFile*)blocks->Item(i)->f);
               
            }
         }   
         
         seq->UnlockDeleteUpdateMutex();
         node = node->GetNext();
      }
   }
   mWaveTrackMutex.Unlock();
   
   //get the new order.
   OrderBlockFiles(tempBlocks);
}
Exemple #5
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);
}
Exemple #6
0
// get the sum of the sizes of all blocks this track list
// references.  However, if a block is referred to multiple
// times it is only counted once.  Return value is in bytes
wxLongLong TrackList::GetSpaceUsage()
{
   // the map guarantees that I only count each block once
   std::map<BlockFile*,wxLongLong> blockFiles;
   for (TrackListNode *p = head; p; p = p->next) {
      if (p->t->GetKind() == Track::Wave) {
         WaveTrack* track = ((WaveTrack*)p->t);
         for (WaveClipList::Node* it=track->GetClipIterator(); it; it=it->GetNext())
         {
            WaveClip* clip = it->GetData();
            BlockArray *blocks = clip->GetSequenceBlockArray();
            for (unsigned int i = 0; i < blocks->GetCount(); i++)
               blockFiles[blocks->Item(i)->f] = blocks->Item(i)->f->GetSpaceUsage();
         }
      }
   }

   std::map<BlockFile*,wxLongLong>::const_iterator bfIter;
   wxLongLong bytes = 0;
   for (bfIter = blockFiles.begin(); bfIter != blockFiles.end(); bfIter++)
      bytes += bfIter->second;

   return bytes;
}
// Given a project, returns a single array of all SeqBlocks
// in the current set of tracks.  Enumerating that array allows
// you to process all block files in the current set.
void GetAllSeqBlocks(AudacityProject *project,
                     BlockArray *outBlocks)
{
   TrackList *tracks = project->GetTracks();
   TrackListIterator iter(tracks);
   Track *t = iter.First();
   while (t) {
      if (t->GetKind() == Track::Wave) {
         WaveTrack *waveTrack = (WaveTrack *)t;
         WaveClipList::compatibility_iterator node = waveTrack->GetClipIterator();
         while(node) {
            WaveClip *clip = node->GetData();
            Sequence *sequence = clip->GetSequence();
            BlockArray *blocks = sequence->GetBlockArray();
            int i;
            for (i = 0; i < (int)blocks->GetCount(); i++)
               outBlocks->Add(blocks->Item(i));
            node = node->GetNext();
         }
      }
      t = iter.Next();
   }
}
Exemple #8
0
bool Sequence::Paste(sampleCount s, const Sequence *src)
{
   if (s < 0)
      s = 0;
   if (s >= mNumSamples)
      s = mNumSamples;

   // Quick check to make sure that it doesn't overflow
   if (((double)mNumSamples) + ((double)src->mNumSamples) > wxLL(9223372036854775807))
      return false;

   BlockArray *srcBlock = src->mBlock;
   sampleCount addedLen = src->mNumSamples;
   unsigned int srcNumBlocks = srcBlock->Count();
   int sampleSize = SAMPLE_SIZE(mSampleFormat);

   if (addedLen == 0 || srcNumBlocks == 0)
      return true;

   unsigned int b = FindBlock(s);
   unsigned int numBlocks = mBlock->Count();

   if (numBlocks == 0 ||
       (s == mNumSamples && mBlock->Item(numBlocks-1)->f->GetLength() >= mMinSamples)) {
      // Special case: this track is currently empty, or it's safe to append
      // onto the end because the current last block is longer than the
      // minimum size

      for (unsigned int i = 0; i < srcNumBlocks; i++)
         AppendBlock(srcBlock->Item(i));

      return ConsistencyCheck(wxT("Paste branch one"));
   }

   if (b >= 0 && b < numBlocks
       && mBlock->Item(b)->f->GetLength() + addedLen < mMaxSamples) {
      // Special case: we can fit all of the new samples inside of
      // one block!

      samplePtr buffer = NewSamples(mMaxSamples, mSampleFormat);

      int splitPoint = s - mBlock->Item(b)->start;
      Read(buffer, mSampleFormat, mBlock->Item(b), 0, splitPoint);
      src->Get(buffer + splitPoint*sampleSize,
               mSampleFormat, 0, addedLen);
      Read(buffer + (splitPoint + addedLen)*sampleSize,
           mSampleFormat, mBlock->Item(b),
           splitPoint, mBlock->Item(b)->f->GetLength() - splitPoint);

      SeqBlock *largerBlock = new SeqBlock();
      largerBlock->start = mBlock->Item(b)->start;
      int largerBlockLen = mBlock->Item(b)->f->GetLength() + addedLen;
      if (largerBlockLen > mMaxSamples) 
         largerBlockLen = mMaxSamples; // Prevent overruns, per NGS report for UmixIt.
      largerBlock->f =
         mDirManager->NewSimpleBlockFile(buffer, largerBlockLen, mSampleFormat);

      mDirManager->Deref(mBlock->Item(b)->f);
      delete mBlock->Item(b);
      mBlock->Item(b) = largerBlock;

      for (unsigned int i = b + 1; i < numBlocks; i++)
         mBlock->Item(i)->start += addedLen;

      mNumSamples += addedLen;

      DeleteSamples(buffer);

      return ConsistencyCheck(wxT("Paste branch two"));
   }

   // Case two: if we are inserting four or fewer blocks,
   // it's simplest to just lump all the data together
   // into one big block along with the split block,
   // then resplit it all
   unsigned int i;

   BlockArray *newBlock = new BlockArray();
   newBlock->Alloc(numBlocks + srcNumBlocks + 2);
   int newNumBlocks = 0;

   for (i = 0; i < b; i++) {
      newBlock->Add(mBlock->Item(i));
      newNumBlocks++;
   }

   SeqBlock *splitBlock = mBlock->Item(b);
   sampleCount splitLen = mBlock->Item(b)->f->GetLength();
   int splitPoint = s - splitBlock->start;

   if (srcNumBlocks <= 4) {

      sampleCount sum = splitLen + addedLen;

      samplePtr sumBuffer = NewSamples(sum, mSampleFormat);
      Read(sumBuffer, mSampleFormat, splitBlock, 0, splitPoint);
      src->Get(sumBuffer + splitPoint * sampleSize,
               mSampleFormat,
               0, addedLen);
      Read(sumBuffer + (splitPoint + addedLen) * sampleSize, mSampleFormat,
           splitBlock, splitPoint,
           splitBlock->f->GetLength() - splitPoint);

      BlockArray *split = Blockify(sumBuffer, sum);
      for (i = 0; i < split->Count(); i++) {
         split->Item(i)->start += splitBlock->start;
         newBlock->Add(split->Item(i));
         newNumBlocks++;
      }
      delete split;
      DeleteSamples(sumBuffer);
   } else {

      // The final case is that we're inserting at least five blocks.
      // We divide these into three groups: the first two get merged
      // with the first half of the split block, the middle ones get
      // copied in as is, and the last two get merged with the last
      // half of the split block.

      sampleCount srcFirstTwoLen =
          srcBlock->Item(0)->f->GetLength() + srcBlock->Item(1)->f->GetLength();
      sampleCount leftLen = splitPoint + srcFirstTwoLen;

      samplePtr leftBuffer = NewSamples(leftLen, mSampleFormat);
      Read(leftBuffer, mSampleFormat, splitBlock, 0, splitPoint);
      src->Get(leftBuffer + splitPoint*sampleSize,
               mSampleFormat, 0, srcFirstTwoLen);

      BlockArray *split = Blockify(leftBuffer, leftLen);
      for (i = 0; i < split->Count(); i++) {
         split->Item(i)->start += splitBlock->start;
         newBlock->Add(split->Item(i));
         newNumBlocks++;
      }
      delete split;
      DeleteSamples(leftBuffer);

      for (i = 2; i < srcNumBlocks - 2; i++) {
         SeqBlock *insertBlock = new SeqBlock();
         insertBlock->start = srcBlock->Item(i)->start + s;

         insertBlock->f = mDirManager->CopyBlockFile(srcBlock->Item(i)->f);
         if (!insertBlock->f) {
            // TODO error: Could not paste!  (Out of disk space?)
            return false;
         }

         newBlock->Add(insertBlock);
         newNumBlocks++;
      }

      sampleCount srcLastTwoLen =
         srcBlock->Item(srcNumBlocks - 2)->f->GetLength() +
         srcBlock->Item(srcNumBlocks - 1)->f->GetLength();
      sampleCount rightSplit = splitBlock->f->GetLength() - splitPoint;
      sampleCount rightLen = rightSplit + srcLastTwoLen;

      samplePtr rightBuffer = NewSamples(rightLen, mSampleFormat);
      sampleCount lastStart = srcBlock->Item(srcNumBlocks - 2)->start;
      src->Get(rightBuffer, mSampleFormat,
               lastStart, srcLastTwoLen);
      Read(rightBuffer + srcLastTwoLen * sampleSize, mSampleFormat,
           splitBlock, splitPoint, rightSplit);

      sampleCount pos = s + lastStart;

      split = Blockify(rightBuffer, rightLen);
      for (i = 0; i < split->Count(); i++) {
         split->Item(i)->start += pos;
         newBlock->Add(split->Item(i));
         newNumBlocks++;
      }
      delete split;
      DeleteSamples(rightBuffer);
   }

   mDirManager->Deref(splitBlock->f);
   delete splitBlock;

   // Copy remaining blocks to new block array and
   // swap the new block array in for the old
   for (i = b + 1; i < numBlocks; i++) {
      mBlock->Item(i)->start += addedLen;
      newBlock->Add(mBlock->Item(i));
      newNumBlocks++;
   }

   delete mBlock;
   mBlock = newBlock;

   mNumSamples += addedLen;

   return ConsistencyCheck(wxT("Paste branch three"));
}
Exemple #9
0
bool Sequence::Delete(sampleCount start, sampleCount len)
{


   if (len == 0)
      return true;
   if (len < 0 || start < 0 || start >= mNumSamples)
      return false;
      
   //TODO: add a ref-deref mechanism to SeqBlock/BlockArray so we don't have to make this a critical section.
   //On-demand threads iterate over the mBlocks and the GUI thread deletes them, so for now put a mutex here over 
   //both functions,
   LockDeleteUpdateMutex();

   unsigned int numBlocks = mBlock->Count();
   unsigned int newNumBlocks = 0;

   unsigned int b0 = FindBlock(start);
   unsigned int b1 = FindBlock(start + len - 1);

   int sampleSize = SAMPLE_SIZE(mSampleFormat);

   // Special case: if the samples to delete are all within a single
   // block and the resulting length is not too small, perform the
   // deletion within this block:
   if (b0 == b1 && mBlock->Item(b0)->f->GetLength() - len >= mMinSamples) {
      SeqBlock *b = mBlock->Item(b0);
      sampleCount pos = start - b->start;
      sampleCount newLen = b->f->GetLength() - len;

      samplePtr buffer = NewSamples(newLen, mSampleFormat);

      Read(buffer, mSampleFormat, b, 0, pos);
      Read(buffer + (pos * sampleSize), mSampleFormat,
           b, pos + len, newLen - pos);

      SeqBlock *newBlock = new SeqBlock();
      newBlock->start = b->start;
      newBlock->f =
         mDirManager->NewSimpleBlockFile(buffer, newLen, mSampleFormat);

      mBlock->Item(b0) = newBlock;

      for (unsigned int j = b0 + 1; j < numBlocks; j++)
         mBlock->Item(j)->start -= len;

      DeleteSamples(buffer);

      mDirManager->Deref(b->f);
      delete b;

      mNumSamples -= len;
      UnlockDeleteUpdateMutex();
      
      return ConsistencyCheck(wxT("Delete - branch one"));
   }

   // Create a new array of blocks
   BlockArray *newBlock = new BlockArray();
   newBlock->Alloc(numBlocks - (b1 - b0) + 2);

   // Copy the blocks before the deletion point over to
   // the new array
   unsigned int i;
   for (i = 0; i < b0; i++) {
      newBlock->Add(mBlock->Item(i));
      newNumBlocks++;
   }

   // First grab the samples in block b0 before the deletion point
   // into preBuffer.  If this is enough samples for its own block,
   // or if this would be the first block in the array, write it out.
   // Otherwise combine it with the previous block (splitting them
   // 50/50 if necessary).
   SeqBlock *preBlock = mBlock->Item(b0);
   sampleCount preBufferLen = start - preBlock->start;
   if (preBufferLen) {
      if (preBufferLen >= mMinSamples || b0 == 0) {
         SeqBlock *insBlock = new SeqBlock();

         insBlock->start = preBlock->start;

         samplePtr preBuffer = NewSamples(preBufferLen, mSampleFormat);
         Read(preBuffer, mSampleFormat, preBlock, 0, preBufferLen);
         insBlock->f =
            mDirManager->NewSimpleBlockFile(preBuffer, preBufferLen, mSampleFormat);
         DeleteSamples(preBuffer);

         newBlock->Add(insBlock);
         newNumBlocks++;

         if (b0 != b1) {
            mDirManager->Deref(preBlock->f);
            delete preBlock;
         }
      } else {
         SeqBlock *prepreBlock = mBlock->Item(b0 - 1);
         sampleCount prepreLen = prepreBlock->f->GetLength();
         sampleCount sum = prepreLen + preBufferLen;

         samplePtr sumBuffer = NewSamples(sum, mSampleFormat);

         Read(sumBuffer, mSampleFormat, prepreBlock, 0, prepreLen);
         Read(sumBuffer + prepreLen*sampleSize, mSampleFormat,
              preBlock, 0, preBufferLen);

         BlockArray *split = Blockify(sumBuffer, sum);
         split->Item(0)->start += prepreBlock->start;
         newBlock->Item(b0 - 1) = split->Item(0);
         for (i = 1; i < split->Count(); i++) {
            split->Item(i)->start += prepreBlock->start;
            newBlock->Add(split->Item(i));
            newNumBlocks++;
         }
         delete split;

         DeleteSamples(sumBuffer);

         mDirManager->Deref(prepreBlock->f);
         delete prepreBlock;

         if (b0 != b1) {
            mDirManager->Deref(preBlock->f);
            delete preBlock;
         }
      }
   } else {
      // The sample where we begin deletion happens to fall
      // right on the beginning of a block.
      if (b0 != b1) {
         mDirManager->Deref(mBlock->Item(b0)->f);
         delete mBlock->Item(b0);
      }
   }

   // Next, delete blocks strictly between b0 and b1
   for (i = b0 + 1; i < b1; i++) {
      mDirManager->Deref(mBlock->Item(i)->f);
      delete mBlock->Item(i);
   }

   // Now, symmetrically, grab the samples in block b1 after the
   // deletion point into postBuffer.  If this is enough samples
   // for its own block, or if this would be the last block in
   // the array, write it out.  Otherwise combine it with the
   // subsequent block (splitting them 50/50 if necessary).
   SeqBlock *postBlock = mBlock->Item(b1);
   sampleCount postBufferLen =
       (postBlock->start + postBlock->f->GetLength()) - (start + len);
   if (postBufferLen) {
      if (postBufferLen >= mMinSamples || b1 == numBlocks - 1) {
         SeqBlock *insBlock = new SeqBlock();

         insBlock->start = start;

         samplePtr postBuffer = NewSamples(postBufferLen, mSampleFormat);
         sampleCount pos = (start + len) - postBlock->start;
         Read(postBuffer, mSampleFormat, postBlock, pos, postBufferLen);
         insBlock->f =
            mDirManager->NewSimpleBlockFile(postBuffer, postBufferLen, mSampleFormat);

         DeleteSamples(postBuffer);

         newBlock->Add(insBlock);
         newNumBlocks++;

         mDirManager->Deref(postBlock->f);
         delete postBlock;
      } else {
         SeqBlock *postpostBlock = mBlock->Item(b1 + 1);
         sampleCount postpostLen = postpostBlock->f->GetLength();
         sampleCount sum = postpostLen + postBufferLen;

         samplePtr sumBuffer = NewSamples(sum, mSampleFormat);
         sampleCount pos = (start + len) - postBlock->start;
         Read(sumBuffer, mSampleFormat, postBlock, pos, postBufferLen);
         Read(sumBuffer + (postBufferLen * sampleSize), mSampleFormat,
              postpostBlock, 0, postpostLen);

         BlockArray *split = Blockify(sumBuffer, sum);
         for (i = 0; i < split->Count(); i++) {
            split->Item(i)->start += start;
            newBlock->Add(split->Item(i));
            newNumBlocks++;
         }
         delete split;
         b1++;

         DeleteSamples(sumBuffer);

         mDirManager->Deref(postpostBlock->f);
         delete postpostBlock;
         mDirManager->Deref(postBlock->f);
         delete postBlock;
      }
   } else {
      // The sample where we begin deletion happens to fall
      // right on the end of a block.
      mDirManager->Deref(mBlock->Item(b1)->f);
      delete mBlock->Item(b1);
   }

   // Copy the remaining blocks over from the old array
   for (i = b1 + 1; i < numBlocks; i++) {
      mBlock->Item(i)->start -= len;
      newBlock->Add(mBlock->Item(i));
      newNumBlocks++;
   }

   // Substitute our new array for the old one
   delete mBlock;
   mBlock = newBlock;

   // Update total number of samples and do a consistency check.
   mNumSamples -= len;
   
   UnlockDeleteUpdateMutex();
   return ConsistencyCheck(wxT("Delete - branch two"));
}
Exemple #10
0
void WaveTrack::Paste(double t, VTrack * src)
{
   wxASSERT(src->GetKind() == WaveTrack::Wave);

   envelope.ExpandRegion(t, src->GetMaxLen());

#if wxUSE_THREADS
   wxMutexLocker lock(*blockMutex);
#endif

   sampleCount s = (sampleCount) ((t - tOffset) * rate + 0.5);

   if (s < 0)
      s = 0;
   if (s >= numSamples)
      s = numSamples;

   BlockArray *srcBlock = ((WaveTrack *) src)->GetBlockArray();
   int addedLen = ((WaveTrack *) src)->numSamples;
   int srcNumBlocks = srcBlock->Count();

   if (addedLen == 0 || srcNumBlocks == 0)
      return;

   int b = FindBlock(s);
   int numBlocks = block->Count();

   if (numBlocks == 0) {
      // Special case: this track is currently empty.

      for (int i = 0; i < srcNumBlocks; i++)
         AppendBlock(srcBlock->Item(i));

      envelope.SetTrackLen(numSamples / rate);

      ConsistencyCheck("Paste branch one");

      return;
   }

   if (b >= 0 && b < numBlocks
       && block->Item(b)->len + addedLen < maxSamples) {
      // Special case: we can fit all of the new samples inside of
      // one block!

      sampleType *buffer = new sampleType[maxSamples];

      int splitPoint = s - block->Item(b)->start;
      Read(buffer, block->Item(b), 0, splitPoint);
      ((WaveTrack *) src)->Get(&buffer[splitPoint], 0, addedLen);
      Read(&buffer[splitPoint + addedLen], block->Item(b),
           splitPoint, block->Item(b)->len - splitPoint);

      WaveBlock *largerBlock = new WaveBlock();
      largerBlock->start = block->Item(b)->start;
      largerBlock->len = block->Item(b)->len + addedLen;
      largerBlock->f = dirManager->NewBlockFile();
      bool inited = InitBlock(largerBlock);
      wxASSERT(inited);

      FirstWrite(buffer, largerBlock, largerBlock->len);

      dirManager->Deref(block->Item(b)->f);
      delete block->Item(b);
      block->Item(b) = largerBlock;

      for (int i = b + 1; i < numBlocks; i++)
         block->Item(i)->start += addedLen;

      numSamples += addedLen;

      delete[]buffer;

      envelope.SetTrackLen(numSamples / rate);

      ConsistencyCheck("Paste branch two");

      return;
   }
   // Case two: if we are inserting four or fewer blocks,
   // it's simplest to just lump all the data together
   // into one big block along with the split block,
   // then resplit it all

   int i;

   BlockArray *newBlock = new BlockArray();
   newBlock->Alloc(numBlocks + srcNumBlocks + 2);
   int newNumBlocks = 0;

   for (i = 0; i < b; i++) {
      newBlock->Add(block->Item(i));
      newNumBlocks++;
   }

   WaveBlock *splitBlock = block->Item(b);
   sampleCount splitLen = block->Item(b)->len;
   int splitPoint = s - splitBlock->start;

   if (srcNumBlocks <= 4) {

      sampleCount sum = splitLen + addedLen;

      sampleType *sumBuffer = new sampleType[sum];

      Read(sumBuffer, splitBlock, 0, splitPoint);
      ((WaveTrack *) src)->Get(&sumBuffer[splitPoint], 0, addedLen);
      Read(&sumBuffer[splitPoint + addedLen], splitBlock,
           splitPoint, splitBlock->len - splitPoint);

      BlockArray *split = Blockify(sumBuffer, sum);
      for (i = 0; i < split->Count(); i++) {
         split->Item(i)->start += splitBlock->start;
         newBlock->Add(split->Item(i));
         newNumBlocks++;
      }
      delete split;

      delete[]sumBuffer;
   } else {

      // The final case is that we're inserting at least five blocks.
      // We divide these into three groups: the first two get merged
      // with the first half of the split block, the middle ones get
      // copied in as is, and the last two get merged with the last
      // half of the split block.

      sampleCount srcFirstTwoLen =
          srcBlock->Item(0)->len + srcBlock->Item(1)->len;
      sampleCount leftLen = splitPoint + srcFirstTwoLen;

      sampleType *leftBuffer = new sampleType[leftLen];

      Read(leftBuffer, splitBlock, 0, splitPoint);
      ((WaveTrack *) src)->Get(&leftBuffer[splitPoint], 0, srcFirstTwoLen);

      BlockArray *split = Blockify(leftBuffer, leftLen);
      for (i = 0; i < split->Count(); i++) {
         split->Item(i)->start += splitBlock->start;
         newBlock->Add(split->Item(i));
         newNumBlocks++;
      }
      delete split;
      delete[]leftBuffer;

      for (i = 2; i < srcNumBlocks - 2; i++) {
         WaveBlock *insertBlock = new WaveBlock();
         insertBlock->start = srcBlock->Item(i)->start + s;
         insertBlock->len = srcBlock->Item(i)->len;
         insertBlock->min = srcBlock->Item(i)->min;
         insertBlock->max = srcBlock->Item(i)->max;
         insertBlock->f = dirManager->CopyBlockFile(srcBlock->Item(i)->f);
         if (!insertBlock->f) {
            wxMessageBox("Could not paste!  (Out of disk space?)");
         }

         newBlock->Add(insertBlock);
         newNumBlocks++;
      }

      sampleCount srcLastTwoLen =
          srcBlock->Item(srcNumBlocks - 2)->len +
          srcBlock->Item(srcNumBlocks - 1)->len;
      sampleCount rightSplit = splitBlock->len - splitPoint;
      sampleCount rightLen = rightSplit + srcLastTwoLen;

      sampleType *rightBuffer = new sampleType[rightLen];

      sampleCount lastStart = srcBlock->Item(srcNumBlocks - 2)->start;
      ((WaveTrack *) src)->Get(rightBuffer, lastStart, srcLastTwoLen);
      Read(&rightBuffer[srcLastTwoLen], splitBlock, splitPoint,
           rightSplit);

      sampleCount pos = s + lastStart;

      split = Blockify(rightBuffer, rightLen);
      for (i = 0; i < split->Count(); i++) {
         split->Item(i)->start += pos;
         newBlock->Add(split->Item(i));
         newNumBlocks++;
      }
      delete split;
      delete[]rightBuffer;
   }

   dirManager->Deref(splitBlock->f);
   delete splitBlock;

   // Copy remaining blocks to new block array and
   // swap the new block array in for the old

   for (i = b + 1; i < numBlocks; i++) {
      block->Item(i)->start += addedLen;
      newBlock->Add(block->Item(i));
      newNumBlocks++;
   }

   delete block;
   block = newBlock;

   numSamples += addedLen;

   envelope.SetTrackLen(numSamples / rate);

   ConsistencyCheck("Paste branch three");
}
Exemple #11
0
void WaveTrack::Delete(sampleCount start, sampleCount len)
{
   if (len == 0)
      return;

   int numBlocks = block->Count();
   int newNumBlocks = 0;

#if wxUSE_THREADS
   wxMutexLocker lock(*blockMutex);
#endif

   int b0 = FindBlock(start);
   int b1 = FindBlock(start + len - 1);

   // Special case: if the samples to delete are all within a single
   // block and the resulting length is not too small, perform the
   // deletion within this block:

   if (b0 == b1 && block->Item(b0)->len - len >= minSamples) {
      WaveBlock *b = block->Item(b0);
      sampleCount pos = start - b->start;
      sampleCount newLen = b->len - len;
      sampleType *buffer = new sampleType[newLen];

      Read(buffer, b, 0, pos);
      Read(&buffer[pos], b, pos + len, newLen - pos);

      WaveBlock *newBlock = NewInitedWaveBlock();
      newBlock->start = b->start;
      newBlock->len = newLen;
      FirstWrite(buffer, newBlock, newLen);

      block->Item(b0) = newBlock;

      for (int j = b0 + 1; j < numBlocks; j++)
         block->Item(j)->start -= len;

      delete[]buffer;

      dirManager->Deref(b->f);
      delete b;

      numSamples -= len;
      envelope.SetTrackLen(numSamples / rate);
      ConsistencyCheck("Delete - branch one");

      return;
   }
   // Create a new array of blocks

   BlockArray *newBlock = new BlockArray();
   newBlock->Alloc(numBlocks - (b1 - b0) + 2);

   // Copy the blocks before the deletion point over to
   // the new array

   int i;
   for (i = 0; i < b0; i++) {
      newBlock->Add(block->Item(i));
      newNumBlocks++;
   }

   // First grab the samples in block b0 before the deletion point
   // into preBuffer.  If this is enough samples for its own block,
   // or if this would be the first block in the array, write it out.
   // Otherwise combine it with the previous block (splitting them
   // 50/50 if necessary).

   WaveBlock *preBlock = block->Item(b0);
   sampleCount preBufferLen = start - preBlock->start;
   if (preBufferLen) {
      if (preBufferLen >= minSamples || b0 == 0) {
         WaveBlock *insBlock = NewInitedWaveBlock();

         insBlock->len = preBufferLen;
         insBlock->start = preBlock->start;

         sampleType *preBuffer = new sampleType[preBufferLen];
         Read(preBuffer, preBlock, 0, preBufferLen);
         FirstWrite(preBuffer, insBlock, preBufferLen);
         delete[]preBuffer;

         newBlock->Add(insBlock);
         newNumBlocks++;

         if (b0 != b1) {
            dirManager->Deref(preBlock->f);
            delete preBlock;
         }
      } else {
         WaveBlock *prepreBlock = block->Item(b0 - 1);
         sampleCount prepreLen = prepreBlock->len;
         sampleCount sum = prepreLen + preBufferLen;

         sampleType *sumBuffer = new sampleType[sum];
         Read(sumBuffer, prepreBlock, 0, prepreLen);
         Read(&sumBuffer[prepreLen], preBlock, 0, preBufferLen);

         BlockArray *split = Blockify(sumBuffer, sum);
         split->Item(0)->start += prepreBlock->start;
         newBlock->Item(b0 - 1) = split->Item(0);
         for (i = 1; i < split->Count(); i++) {
            split->Item(i)->start += prepreBlock->start;
            newBlock->Add(split->Item(i));
            newNumBlocks++;
         }
         delete split;

         delete[]sumBuffer;

         dirManager->Deref(prepreBlock->f);
         delete prepreBlock;

         if (b0 != b1) {
            dirManager->Deref(preBlock->f);
            delete preBlock;
         }
      }
   } else {
      // The sample where we begin deletion happens to fall
      // right on the beginning of a block.

      if (b0 != b1) {
         dirManager->Deref(block->Item(b0)->f);
         delete block->Item(b0);
      }
   }

   // Next, delete blocks strictly between b0 and b1

   for (i = b0 + 1; i < b1; i++) {
      dirManager->Deref(block->Item(i)->f);
      delete block->Item(i);
   }

   // Now, symmetrically, grab the samples in block b1 after the
   // deletion point into postBuffer.  If this is enough samples
   // for its own block, or if this would be the last block in
   // the array, write it out.  Otherwise combine it with the
   // subsequent block (splitting them 50/50 if necessary).

   WaveBlock *postBlock = block->Item(b1);
   sampleCount postBufferLen =
       (postBlock->start + postBlock->len) - (start + len);
   if (postBufferLen) {
      if (postBufferLen >= minSamples || b1 == numBlocks - 1) {
         WaveBlock *insBlock = NewInitedWaveBlock();

         insBlock->len = postBufferLen;
         insBlock->start = start;

         sampleType *postBuffer = new sampleType[postBufferLen];
         sampleCount pos = (start + len) - postBlock->start;
         Read(postBuffer, postBlock, pos, postBufferLen);
         FirstWrite(postBuffer, insBlock, postBufferLen);
         delete[]postBuffer;

         newBlock->Add(insBlock);
         newNumBlocks++;

         dirManager->Deref(postBlock->f);
         delete postBlock;
      } else {
         WaveBlock *postpostBlock = block->Item(b1 + 1);
         sampleCount postpostLen = postpostBlock->len;
         sampleCount sum = postpostLen + postBufferLen;

         sampleType *sumBuffer = new sampleType[sum];
         sampleCount pos = (start + len) - postBlock->start;
         Read(sumBuffer, postBlock, pos, postBufferLen);
         Read(&sumBuffer[postBufferLen], postpostBlock, 0, postpostLen);

         BlockArray *split = Blockify(sumBuffer, sum);
         for (i = 0; i < split->Count(); i++) {
            split->Item(i)->start += start;
            newBlock->Add(split->Item(i));
            newNumBlocks++;
         }
         delete split;
         b1++;

         delete[]sumBuffer;

         dirManager->Deref(postpostBlock->f);
         delete postpostBlock;
         dirManager->Deref(postBlock->f);
         delete postBlock;
      }
   } else {
      // The sample where we begin deletion happens to fall
      // right on the end of a block.

      if (b0 != b1) {
         dirManager->Deref(block->Item(b1)->f);
         delete block->Item(b1);
      }
   }

   // Copy the remaining blocks over from the old array

   for (i = b1 + 1; i < numBlocks; i++) {
      block->Item(i)->start -= len;
      newBlock->Add(block->Item(i));
      newNumBlocks++;
   }

   // Substitute our new array for the old one

   delete block;
   block = newBlock;

   // Update total number of samples, update the envelope,
   // and do a consistency check.

   numSamples -= len;
   envelope.SetTrackLen(numSamples / rate);
   ConsistencyCheck("Delete - branch two");
}
///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.
            seq->LockDeleteUpdateMutex();

            //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->GetCount(); i++)
            {
               //if there is data but no summary, this blockfile needs summarizing.
               if(blocks->Item(i)->f->IsDataAvailable() && !blocks->Item(i)->f->IsSummaryAvailable())
               {
                  blocks->Item(i)->f->Ref();
                  ((ODPCMAliasBlockFile*)blocks->Item(i)->f)->SetStart(blocks->Item(i)->start);
                  ((ODPCMAliasBlockFile*)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)(((ODPCMAliasBlockFile*)blocks->Item(i)->f)->GetStart()+((ODPCMAliasBlockFile*)blocks->Item(i)->f)->GetClipOffset()))
                     insertCursor++;

                  tempBlocks.insert(tempBlocks.begin()+insertCursor++,(ODPCMAliasBlockFile*)blocks->Item(i)->f);
               }
            }
            seq->UnlockDeleteUpdateMutex();
            node = node->GetNext();
         }
      }
   }
   mWaveTrackMutex.Unlock();

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

   MarkUpdateRan();
}