int EffectNyquist::GetCallback(float *buffer, int ch, long start, long len, long totlen) { if (mCurBuffer[ch]) { if ((mCurStart[ch] + start) < mCurBufferStart[ch] || (mCurStart[ch] + start)+len > mCurBufferStart[ch]+mCurBufferLen[ch]) { delete[] mCurBuffer[ch]; mCurBuffer[ch] = NULL; } } if (!mCurBuffer[ch]) { mCurBufferStart[ch] = (mCurStart[ch] + start); mCurBufferLen[ch] = mCurTrack[ch]->GetBestBlockSize(mCurBufferStart[ch]); if (mCurBufferLen[ch] < len) { mCurBufferLen[ch] = mCurTrack[ch]->GetIdealBlockSize(); } if (mCurBufferStart[ch] + mCurBufferLen[ch] > mCurStart[ch] + mCurLen) { mCurBufferLen[ch] = mCurStart[ch] + mCurLen - mCurBufferStart[ch]; } mCurBuffer[ch] = NewSamples(mCurBufferLen[ch], floatSample); if (!mCurTrack[ch]->Get(mCurBuffer[ch], floatSample, mCurBufferStart[ch], mCurBufferLen[ch])) { wxPrintf(wxT("GET error\n")); return -1; } } long offset = (mCurStart[ch] + start) - mCurBufferStart[ch]; CopySamples(mCurBuffer[ch] + offset*SAMPLE_SIZE(floatSample), floatSample, (samplePtr)buffer, floatSample, len); if (ch == 0) { double progress = mScale*(((float)start+len)/mCurLen); if (progress > mProgressIn) { mProgressIn = progress; } if (TotalProgress(mProgressIn+mProgressOut+mProgressTot)) { return -1; } } return 0; }
int EffectNyquist::PutCallback(float *buffer, int channel, long start, long len, long totlen) { if (channel == 0) { double progress = mScale*((float)(start+len)/totlen); if (progress > mProgressOut) { mProgressOut = progress; } if (TotalProgress(mProgressIn+mProgressOut+mProgressTot)) { return -1; } } if (mOutputTrack[channel]->Append((samplePtr)buffer, floatSample, len)) { return 0; // success } return -1; // failure }
bool EffectTruncSilence::Analyze(RegionList& silenceList, RegionList& trackSilences, WaveTrack* wt, sampleCount* silentFrame, sampleCount* index, int whichTrack, double* inputLength /*= NULL*/, double* minInputLength /*= NULL*/) { // Smallest silent region to detect in frames sampleCount minSilenceFrames = sampleCount(std::max( mInitialAllowedSilence, DEF_MinTruncMs) * wt->GetRate()); double truncDbSilenceThreshold = Enums::Db2Signal[mTruncDbChoiceIndex]; sampleCount blockLen = wt->GetMaxBlockSize(); sampleCount start = wt->TimeToLongSamples(mT0); sampleCount end = wt->TimeToLongSamples(mT1); sampleCount outLength = 0; double previewLength; gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &previewLength, 6.0); // Minimum required length in samples. const sampleCount previewLen = previewLength * wt->GetRate(); // Keep position in overall silences list for optimization RegionList::iterator rit(silenceList.begin()); // Allocate buffer float *buffer = new float[blockLen]; // Loop through current track while (*index < end) { if (inputLength && ((outLength >= previewLen) || (*index - start > wt->TimeToLongSamples(*minInputLength)))) { *inputLength = std::min<double>(*inputLength, *minInputLength); if (outLength >= previewLen) { *minInputLength = *inputLength; } return true; } if (!inputLength) { // Show progress dialog, test for cancellation bool cancelled = TotalProgress( detectFrac * (whichTrack + (*index - start) / (double)(end - start)) / (double)GetNumWaveTracks()); if (cancelled) { delete [] buffer; return false; } } // Optimization: if not in a silent region skip ahead to the next one double curTime = wt->LongSamplesToTime(*index); for ( ; rit != silenceList.end(); ++rit) { // Find the first silent region ending after current time if (rit->end >= curTime) { break; } } if (rit == silenceList.end()) { // No more regions -- no need to process the rest of the track if (inputLength) { // Add available samples up to previewLength. sampleCount remainingTrackSamples = wt->TimeToLongSamples(wt->GetEndTime()) - *index; sampleCount requiredTrackSamples = previewLen - outLength; outLength += (remainingTrackSamples > requiredTrackSamples)? requiredTrackSamples : remainingTrackSamples; } break; } else if (rit->start > curTime) { // End current silent region, skip ahead if (*silentFrame >= minSilenceFrames) { trackSilences.push_back(Region( wt->LongSamplesToTime(*index - *silentFrame), wt->LongSamplesToTime(*index) )); } *silentFrame = 0; sampleCount newIndex = wt->TimeToLongSamples(rit->start); if (inputLength) { sampleCount requiredTrackSamples = previewLen - outLength; // Add non-silent sample to outLength outLength += ((newIndex - *index) > requiredTrackSamples)? requiredTrackSamples : newIndex - *index; } *index = newIndex; } // End of optimization // Limit size of current block if we've reached the end sampleCount count = blockLen; if ((*index + count) > end) { count = end - *index; } // Fill buffer wt->Get((samplePtr)(buffer), floatSample, *index, count); // Look for silenceList in current block for (sampleCount i = 0; i < count; ++i) { if (inputLength && ((outLength >= previewLen) || (outLength > wt->TimeToLongSamples(*minInputLength)))) { *inputLength = wt->LongSamplesToTime(*index + i) - wt->LongSamplesToTime(start); break; } if (fabs(buffer[i]) < truncDbSilenceThreshold) { (*silentFrame)++; } else { sampleCount allowed = 0; if (*silentFrame >= minSilenceFrames) { if (inputLength) { switch (mActionIndex) { case kTruncate: outLength += wt->TimeToLongSamples(mTruncLongestAllowedSilence); break; case kCompress: allowed = wt->TimeToLongSamples(mInitialAllowedSilence); outLength += allowed + (*silentFrame - allowed) * mSilenceCompressPercent / 100.0; break; // default: // Not currently used. } } // Record the silent region Region *r = new Region; r->start = wt->LongSamplesToTime(*index + i - *silentFrame); r->end = wt->LongSamplesToTime(*index + i); trackSilences.push_back(Region( wt->LongSamplesToTime(*index + i - *silentFrame), wt->LongSamplesToTime(*index + i) )); } else if (inputLength) { // included as part of non-silence outLength += *silentFrame; } *silentFrame = 0; if (inputLength) { ++outLength; // Add non-silent sample to outLength } } } // Next block *index += count; } delete [] buffer; if (inputLength) { *inputLength = std::min<double>(*inputLength, *minInputLength); if (outLength >= previewLen) { *minInputLength = *inputLength; } } return true; }
bool EffectTruncSilence::DoRemoval (const RegionList &silences, unsigned iGroup, unsigned nGroups, Track *firstTrack, Track *lastTrack, double &totalCutLen) { // // Now remove the silent regions from all selected / sync-lock selected tracks. // // Loop over detected regions in reverse (so cuts don't change time values // down the line) int whichReg = 0; RegionList::const_reverse_iterator rit; for (rit = silences.rbegin(); rit != silences.rend(); ++rit) { const Region ®ion = *rit; const Region *const r = ®ion; // Progress dialog and cancellation. Do additional cleanup before return. const double frac = detectFrac + (1 - detectFrac) * (iGroup + whichReg / double(silences.size())) / nGroups; if (TotalProgress(frac)) { ReplaceProcessedTracks(false); return false; } // Intersection may create regions smaller than allowed; ignore them. // Allow one nanosecond extra for consistent results with exact milliseconds of allowed silence. if ((r->end - r->start) < (mInitialAllowedSilence - 0.000000001)) continue; // Find NEW silence length as requested double inLength = r->end - r->start; double outLength; switch (mActionIndex) { case kTruncate: outLength = std::min(mTruncLongestAllowedSilence, inLength); break; case kCompress: outLength = mInitialAllowedSilence + (inLength - mInitialAllowedSilence) * mSilenceCompressPercent / 100.0; break; default: // Not currently used. outLength = std::min(mInitialAllowedSilence + (inLength - mInitialAllowedSilence) * mSilenceCompressPercent / 100.0, mTruncLongestAllowedSilence); } double cutLen = inLength - outLength; totalCutLen += cutLen; TrackListIterator iterOut(mOutputTracks); bool lastSeen = false; for (Track *t = iterOut.StartWith(firstTrack); t && !lastSeen; t = iterOut.Next()) { lastSeen = (t == lastTrack); if (!(t->GetSelected() || t->IsSyncLockSelected())) continue; // Don't waste time past the end of a track if (t->GetEndTime() < r->start) continue; double cutStart = (r->start + r->end - cutLen) / 2; double cutEnd = cutStart + cutLen; if (t->GetKind() == Track::Wave) { // In WaveTracks, clear with a cross-fade WaveTrack *const wt = static_cast<WaveTrack*>(t); sampleCount blendFrames = mBlendFrameCount; // Round start/end times to frame boundaries cutStart = wt->LongSamplesToTime(wt->TimeToLongSamples(cutStart)); cutEnd = wt->LongSamplesToTime(wt->TimeToLongSamples(cutEnd)); // Make sure the cross-fade does not affect non-silent frames if (wt->LongSamplesToTime(blendFrames) > inLength) { blendFrames = wt->TimeToLongSamples(inLength); } // Perform cross-fade in memory float *buf1 = new float[blendFrames]; float *buf2 = new float[blendFrames]; sampleCount t1 = wt->TimeToLongSamples(cutStart) - blendFrames / 2; sampleCount t2 = wt->TimeToLongSamples(cutEnd) - blendFrames / 2; wt->Get((samplePtr)buf1, floatSample, t1, blendFrames); wt->Get((samplePtr)buf2, floatSample, t2, blendFrames); for (sampleCount i = 0; i < blendFrames; ++i) { buf1[i] = ((blendFrames-i) * buf1[i] + i * buf2[i]) / (double)blendFrames; } // Perform the cut wt->Clear(cutStart, cutEnd); // Write cross-faded data wt->Set((samplePtr)buf1, floatSample, t1, blendFrames); delete [] buf1; delete [] buf2; } else // Non-wave tracks: just do a sync-lock adjust t->SyncLockAdjust(cutEnd, cutStart); } ++whichReg; } return true; }
bool Effect::TrackGroupProgress(int whichGroup, double frac) { return TotalProgress((whichGroup+frac)/mNumGroups); }
bool Effect::TrackProgress(int whichTrack, double frac) { return TotalProgress((whichTrack+frac)/mNumTracks); }
// this currently does an exponential fade bool EffectAutoDuck::ApplyDuckFade(int trackNumber, WaveTrack* t, double t0, double t1) { bool cancel = false; sampleCount start = t->TimeToLongSamples(t0); sampleCount end = t->TimeToLongSamples(t1); float *buf = new float[kBufSize]; sampleCount pos = start; int fadeDownSamples = t->TimeToLongSamples( mOuterFadeDownLen + mInnerFadeDownLen); if (fadeDownSamples < 1) fadeDownSamples = 1; int fadeUpSamples = t->TimeToLongSamples( mOuterFadeUpLen + mInnerFadeUpLen); if (fadeUpSamples < 1) fadeUpSamples = 1; float fadeDownStep = mDuckAmountDb / fadeDownSamples; float fadeUpStep = mDuckAmountDb / fadeUpSamples; while (pos < end) { sampleCount len = end - pos; if (len > kBufSize) len = kBufSize; t->Get((samplePtr)buf, floatSample, pos, len); for (sampleCount i = pos; i < pos + len; i++) { float gainDown = fadeDownStep * (i - start); float gainUp = fadeUpStep * (end - i);; float gain; if (gainDown > gainUp) gain = gainDown; else gain = gainUp; if (gain < mDuckAmountDb) gain = mDuckAmountDb; buf[i - pos] *= DB_TO_LINEAR(gain); } t->Set((samplePtr)buf, floatSample, pos, len); pos += len; float curTime = t->LongSamplesToTime(pos); float fractionFinished = (curTime - mT0) / (mT1 - mT0); if (TotalProgress( (trackNumber + 1 + fractionFinished) / (GetNumWaveTracks() + 1) )) { cancel = true; break; } } delete[] buf; return cancel; }
bool EffectAutoDuck::Process() { sampleCount i; if (GetNumWaveTracks() == 0 || !mControlTrack) return false; bool cancel = false; sampleCount start = mControlTrack->TimeToLongSamples(mT0 + mOuterFadeDownLen); sampleCount end = mControlTrack->TimeToLongSamples(mT1 - mOuterFadeUpLen); if (end <= start) return false; // the minimum number of samples we have to wait until the maximum // pause has been exceeded double maxPause = mMaximumPause; // We don't fade in until we have time enough to actually fade out again if (maxPause < mOuterFadeDownLen + mOuterFadeUpLen) maxPause = mOuterFadeDownLen + mOuterFadeUpLen; sampleCount minSamplesPause = mControlTrack->TimeToLongSamples(maxPause); double threshold = DB_TO_LINEAR(mThresholdDb); // adjust the threshold so we can compare it to the rmsSum value threshold = threshold * threshold * kRMSWindowSize; int rmsPos = 0; float rmsSum = 0; float *rmsWindow = new float[kRMSWindowSize]; for (i = 0; i < kRMSWindowSize; i++) rmsWindow[i] = 0; float *buf = new float[kBufSize]; bool inDuckRegion = false; // initialize the following two variables to prevent compiler warning double duckRegionStart = 0; sampleCount curSamplesPause = 0; // to make the progress bar appear more natural, we first look for all // duck regions and apply them all at once afterwards AutoDuckRegionArray regions; sampleCount pos = start; while (pos < end) { sampleCount len = end - pos; if (len > kBufSize) len = kBufSize; mControlTrack->Get((samplePtr)buf, floatSample, pos, (sampleCount)len); for (i = pos; i < pos + len; i++) { rmsSum -= rmsWindow[rmsPos]; rmsWindow[rmsPos] = buf[i - pos] * buf[i - pos]; rmsSum += rmsWindow[rmsPos]; rmsPos = (rmsPos + 1) % kRMSWindowSize; bool thresholdExceeded = rmsSum > threshold; if (thresholdExceeded) { // everytime the threshold is exceeded, reset our count for // the number of pause samples curSamplesPause = 0; if (!inDuckRegion) { // the threshold has been exceeded for the first time, so // let the duck region begin here inDuckRegion = true; duckRegionStart = mControlTrack->LongSamplesToTime(i); } } if (!thresholdExceeded && inDuckRegion) { // the threshold has not been exceeded and we are in a duck // region, but only fade in if the maximum pause has been // exceeded curSamplesPause += 1; if (curSamplesPause >= minSamplesPause) { // do the actual duck fade and reset all values double duckRegionEnd = mControlTrack->LongSamplesToTime(i - curSamplesPause); regions.Add(AutoDuckRegion( duckRegionStart - mOuterFadeDownLen, duckRegionEnd + mOuterFadeUpLen)); inDuckRegion = false; } } } pos += len; if (TotalProgress( ((double)(pos-start)) / (end-start) / (GetNumWaveTracks() + 1) )) { cancel = true; break; } } // apply last duck fade, if any if (inDuckRegion) { double duckRegionEnd = mControlTrack->LongSamplesToTime(end - curSamplesPause); regions.Add(AutoDuckRegion( duckRegionStart - mOuterFadeDownLen, duckRegionEnd + mOuterFadeUpLen)); } delete[] buf; delete[] rmsWindow; if (!cancel) { CopyInputTracks(); // Set up mOutputTracks. SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks); Track *iterTrack = iter.First(); int trackNumber = 0; while (iterTrack) { wxASSERT(iterTrack->GetKind() == Track::Wave); WaveTrack* t = (WaveTrack*)iterTrack; for (i = 0; i < (int)regions.GetCount(); i++) { const AutoDuckRegion& region = regions[i]; if (ApplyDuckFade(trackNumber, t, region.t0, region.t1)) { cancel = true; break; } } if (cancel) break; iterTrack = iter.Next(); trackNumber++; } } ReplaceProcessedTracks(!cancel); return !cancel; }
//ProcessOne() takes a track, transforms it to bunch of buffer-blocks, //and executes ProcessSimpleMono on these blocks bool EffectTwoPassSimpleMono::ProcessOne(WaveTrack * track, sampleCount start, sampleCount end) { bool ret; sampleCount s, samples1, samples2, tmpcount; float *tmpfloat; //Get the length of the buffer (as double). len is //used simple to calculate a progress meter, so it is easier //to make it a double now than it is to do it later double len = (double)(end - start); sampleCount maxblock = track->GetMaxBlockSize(); //Initiate a processing buffer. This buffer will (most likely) //be shorter than the length of the track being processed. float *buffer1 = new float[maxblock]; float *buffer2 = new float[maxblock]; samples1 = track->GetBestBlockSize(start); if(start + samples1 > end) samples1 = end - start; if(samples1 > maxblock) samples1 = maxblock; //Get the samples from the track and put them in the buffer track->Get((samplePtr) buffer1, floatSample, start, samples1); // Process the first buffer with a NULL previous buffer if (mPass == 0) ret = TwoBufferProcessPass1(NULL, 0, buffer1, samples1); else ret = TwoBufferProcessPass2(NULL, 0, buffer1, samples1); if (!ret) { delete[]buffer1; delete[]buffer2; //Return false because the effect failed. return false; } //Go through the track one buffer at a time. s counts which //sample the current buffer starts at. s = start + samples1; while (s < end) { //Get a block of samples (smaller than the size of the buffer) samples2 = track->GetBestBlockSize(s); if(samples2 > maxblock) samples2 = maxblock; //Adjust the block size if it is the final block in the track if (s + samples2 > end) samples2 = end - s; //Get the samples from the track and put them in the buffer track->Get((samplePtr) buffer2, floatSample, s, samples2); //Process the buffer. If it fails, clean up and exit. if (mPass == 0) ret = TwoBufferProcessPass1(buffer1, samples1, buffer2, samples2); else ret = TwoBufferProcessPass2(buffer1, samples1, buffer2, samples2); if (!ret) { delete[]buffer1; delete[]buffer2; //Return false because the effect failed. return false; } //Processing succeeded. copy the newly-changed samples back //onto the track. track->Set((samplePtr) buffer1, floatSample, s-samples1, samples1); //Increment s one blockfull of samples s += samples2; //Update the Progress meter if (mSecondPassDisabled) ret = TotalProgress((mCurTrackNum + (s-start)/len) / GetNumWaveTracks()); else ret = TotalProgress((mCurTrackNum + (s-start)/len + GetNumWaveTracks()*mPass)/ (GetNumWaveTracks()*2)); if (ret) { delete[]buffer1; delete[]buffer2; //Return false because the effect failed. return false; } // Rotate the buffers tmpfloat = buffer1; buffer1 = buffer2; buffer2 = tmpfloat; tmpcount = samples1; samples1 = samples2; samples2 = tmpcount; } // Send the last buffer with a NULL pointer for the current buffer if (mPass == 0) ret = TwoBufferProcessPass1(buffer1, samples1, NULL, 0); else ret = TwoBufferProcessPass2(buffer1, samples1, NULL, 0); if (!ret) { delete[]buffer1; delete[]buffer2; //Return false because the effect failed. return false; } //Processing succeeded. copy the newly-changed samples back //onto the track. track->Set((samplePtr) buffer1, floatSample, s-samples1, samples1); //Clean up the buffer delete[]buffer1; delete[]buffer2; //Return true because the effect processing succeeded. return true; }
bool EffectTruncSilence::Process() { // Typical fraction of total time taken by detection (better to guess low) const double detectFrac = .4; // Copy tracks this->CopyInputTracks(Track::All); // Lower bound on the amount of silence to find at a time -- this avoids // detecting silence repeatedly in low-frequency sounds. const double minTruncMs = 0.001; double truncDbSilenceThreshold = Enums::Db2Signal[mTruncDbChoiceIndex]; // Master list of silent regions; it is responsible for deleting them. // This list should always be kept in order. RegionList silences; silences.DeleteContents(true); // Start with the whole selection silent Region *sel = new Region; sel->start = mT0; sel->end = mT1; silences.push_back(sel); // Remove non-silent regions in each track SelectedTrackListOfKindIterator iter(Track::Wave, mTracks); int whichTrack = 0; for (Track *t = iter.First(); t; t = iter.Next()) { WaveTrack *wt = (WaveTrack *)t; // Smallest silent region to detect in frames sampleCount minSilenceFrames = sampleCount(wxMax( mInitialAllowedSilence, minTruncMs) * wt->GetRate()); // // Scan the track for silences // RegionList trackSilences; trackSilences.DeleteContents(true); sampleCount blockLen = wt->GetMaxBlockSize(); sampleCount start = wt->TimeToLongSamples(mT0); sampleCount end = wt->TimeToLongSamples(mT1); // Allocate buffer float *buffer = new float[blockLen]; sampleCount index = start; sampleCount silentFrames = 0; bool cancelled = false; // Keep position in overall silences list for optimization RegionList::iterator rit(silences.begin()); while (index < end) { // Show progress dialog, test for cancellation cancelled = TotalProgress( detectFrac * (whichTrack + index / (double)end) / (double)GetNumWaveTracks()); if (cancelled) break; // // Optimization: if not in a silent region skip ahead to the next one // double curTime = wt->LongSamplesToTime(index); for ( ; rit != silences.end(); ++rit) { // Find the first silent region ending after current time if ((*rit)->end >= curTime) break; } if (rit == silences.end()) { // No more regions -- no need to process the rest of the track break; } else if ((*rit)->start > curTime) { // End current silent region, skip ahead if (silentFrames >= minSilenceFrames) { Region *r = new Region; r->start = wt->LongSamplesToTime(index - silentFrames); r->end = wt->LongSamplesToTime(index); trackSilences.push_back(r); } silentFrames = 0; index = wt->TimeToLongSamples((*rit)->start); } // // End of optimization // // Limit size of current block if we've reached the end sampleCount count = blockLen; if ((index + count) > end) { count = end - index; } // Fill buffer wt->Get((samplePtr)(buffer), floatSample, index, count); // Look for silences in current block for (sampleCount i = 0; i < count; ++i) { if (fabs(buffer[i]) < truncDbSilenceThreshold) { ++silentFrames; } else { if (silentFrames >= minSilenceFrames) { // Record the silent region Region *r = new Region; r->start = wt->LongSamplesToTime(index + i - silentFrames); r->end = wt->LongSamplesToTime(index + i); trackSilences.push_back(r); } silentFrames = 0; } } // Next block index += count; } delete [] buffer; // Buffer has been freed, so we're OK to return if cancelled if (cancelled) { ReplaceProcessedTracks(false); return false; } if (silentFrames >= minSilenceFrames) { // Track ended in silence -- record region Region *r = new Region; r->start = wt->LongSamplesToTime(index - silentFrames); r->end = wt->LongSamplesToTime(index); trackSilences.push_back(r); } // Intersect with the overall silent region list Intersect(silences, trackSilences); whichTrack++; } // // Now remove the silent regions from all selected / sync-lock selected tracks. // // Loop over detected regions in reverse (so cuts don't change time values // down the line) int whichReg = 0; RegionList::reverse_iterator rit; double totalCutLen = 0.0; // For cutting selection at the end for (rit = silences.rbegin(); rit != silences.rend(); ++rit) { Region *r = *rit; // Progress dialog and cancellation. Do additional cleanup before return. if (TotalProgress(detectFrac + (1 - detectFrac) * whichReg / (double)silences.size())) { ReplaceProcessedTracks(false); return false; } // Intersection may create regions smaller than allowed; ignore them. // Allow one nanosecond extra for consistent results with exact milliseconds of allowed silence. if ((r->end - r->start) < (mInitialAllowedSilence - 0.000000001)) continue; // Find new silence length as requested double inLength = r->end - r->start; double outLength; switch (mProcessIndex) { case 0: outLength = wxMin(mTruncLongestAllowedSilence, inLength); break; case 1: outLength = mInitialAllowedSilence + (inLength - mInitialAllowedSilence) * mSilenceCompressPercent / 100.0; break; default: // Not currently used. outLength = wxMin(mInitialAllowedSilence + (inLength - mInitialAllowedSilence) * mSilenceCompressPercent / 100.0, mTruncLongestAllowedSilence); } double cutLen = inLength - outLength; totalCutLen += cutLen; TrackListIterator iterOut(mOutputTracks); for (Track *t = iterOut.First(); t; t = iterOut.Next()) { // Don't waste time past the end of a track if (t->GetEndTime() < r->start) continue; if (t->GetKind() == Track::Wave && ( t->GetSelected() || t->IsSyncLockSelected())) { // In WaveTracks, clear with a cross-fade WaveTrack *wt = (WaveTrack *)t; sampleCount blendFrames = mBlendFrameCount; double cutStart = (r->start + r->end - cutLen) / 2; double cutEnd = cutStart + cutLen; // Round start/end times to frame boundaries cutStart = wt->LongSamplesToTime(wt->TimeToLongSamples(cutStart)); cutEnd = wt->LongSamplesToTime(wt->TimeToLongSamples(cutEnd)); // Make sure the cross-fade does not affect non-silent frames if (wt->LongSamplesToTime(blendFrames) > inLength) { blendFrames = wt->TimeToLongSamples(inLength); } // Perform cross-fade in memory float *buf1 = new float[blendFrames]; float *buf2 = new float[blendFrames]; sampleCount t1 = wt->TimeToLongSamples(cutStart) - blendFrames / 2; sampleCount t2 = wt->TimeToLongSamples(cutEnd) - blendFrames / 2; wt->Get((samplePtr)buf1, floatSample, t1, blendFrames); wt->Get((samplePtr)buf2, floatSample, t2, blendFrames); for (sampleCount i = 0; i < blendFrames; ++i) { buf1[i] = ((blendFrames-i) * buf1[i] + i * buf2[i]) / (double)blendFrames; } // Perform the cut wt->Clear(cutStart, cutEnd); // Write cross-faded data wt->Set((samplePtr)buf1, floatSample, t1, blendFrames); delete [] buf1; delete [] buf2; } else if (t->GetSelected() || t->IsSyncLockSelected()) { // Non-wave tracks: just do a sync-lock adjust double cutStart = (r->start + r->end - cutLen) / 2; double cutEnd = cutStart + cutLen; t->SyncLockAdjust(cutEnd, cutStart); } } ++whichReg; } mT1 -= totalCutLen; ReplaceProcessedTracks(true); return true; }
// this currently does an exponential fade bool EffectAutoDuck::ApplyDuckFade(int trackNum, WaveTrack* t, double t0, double t1) { bool cancel = false; auto start = t->TimeToLongSamples(t0); auto end = t->TimeToLongSamples(t1); Floats buf{ kBufSize }; auto pos = start; auto fadeDownSamples = t->TimeToLongSamples( mOuterFadeDownLen + mInnerFadeDownLen); if (fadeDownSamples < 1) fadeDownSamples = 1; auto fadeUpSamples = t->TimeToLongSamples( mOuterFadeUpLen + mInnerFadeUpLen); if (fadeUpSamples < 1) fadeUpSamples = 1; float fadeDownStep = mDuckAmountDb / fadeDownSamples.as_double(); float fadeUpStep = mDuckAmountDb / fadeUpSamples.as_double(); while (pos < end) { const auto len = limitSampleBufferSize( kBufSize, end - pos ); t->Get((samplePtr)buf.get(), floatSample, pos, len); for (auto i = pos; i < pos + len; i++) { float gainDown = fadeDownStep * (i - start).as_float(); float gainUp = fadeUpStep * (end - i).as_float(); float gain; if (gainDown > gainUp) gain = gainDown; else gain = gainUp; if (gain < mDuckAmountDb) gain = mDuckAmountDb; // i - pos is bounded by len: buf[ ( i - pos ).as_size_t() ] *= DB_TO_LINEAR(gain); } t->Set((samplePtr)buf.get(), floatSample, pos, len); pos += len; float curTime = t->LongSamplesToTime(pos); float fractionFinished = (curTime - mT0) / (mT1 - mT0); if (TotalProgress( (trackNum + 1 + fractionFinished) / (GetNumWaveTracks() + 1) )) { cancel = true; break; } } return cancel; }
bool EffectAutoDuck::Process() { if (GetNumWaveTracks() == 0 || !mControlTrack) return false; bool cancel = false; auto start = mControlTrack->TimeToLongSamples(mT0 + mOuterFadeDownLen); auto end = mControlTrack->TimeToLongSamples(mT1 - mOuterFadeUpLen); if (end <= start) return false; // the minimum number of samples we have to wait until the maximum // pause has been exceeded double maxPause = mMaximumPause; // We don't fade in until we have time enough to actually fade out again if (maxPause < mOuterFadeDownLen + mOuterFadeUpLen) maxPause = mOuterFadeDownLen + mOuterFadeUpLen; auto minSamplesPause = mControlTrack->TimeToLongSamples(maxPause); double threshold = DB_TO_LINEAR(mThresholdDb); // adjust the threshold so we can compare it to the rmsSum value threshold = threshold * threshold * kRMSWindowSize; int rmsPos = 0; float rmsSum = 0; // to make the progress bar appear more natural, we first look for all // duck regions and apply them all at once afterwards std::vector<AutoDuckRegion> regions; bool inDuckRegion = false; { Floats rmsWindow{ kRMSWindowSize, true }; Floats buf{ kBufSize }; // initialize the following two variables to prevent compiler warning double duckRegionStart = 0; sampleCount curSamplesPause = 0; auto pos = start; while (pos < end) { const auto len = limitSampleBufferSize( kBufSize, end - pos ); mControlTrack->Get((samplePtr)buf.get(), floatSample, pos, len); for (auto i = pos; i < pos + len; i++) { rmsSum -= rmsWindow[rmsPos]; // i - pos is bounded by len: auto index = ( i - pos ).as_size_t(); rmsWindow[rmsPos] = buf[ index ] * buf[ index ]; rmsSum += rmsWindow[rmsPos]; rmsPos = (rmsPos + 1) % kRMSWindowSize; bool thresholdExceeded = rmsSum > threshold; if (thresholdExceeded) { // everytime the threshold is exceeded, reset our count for // the number of pause samples curSamplesPause = 0; if (!inDuckRegion) { // the threshold has been exceeded for the first time, so // let the duck region begin here inDuckRegion = true; duckRegionStart = mControlTrack->LongSamplesToTime(i); } } if (!thresholdExceeded && inDuckRegion) { // the threshold has not been exceeded and we are in a duck // region, but only fade in if the maximum pause has been // exceeded curSamplesPause += 1; if (curSamplesPause >= minSamplesPause) { // do the actual duck fade and reset all values double duckRegionEnd = mControlTrack->LongSamplesToTime(i - curSamplesPause); regions.push_back(AutoDuckRegion( duckRegionStart - mOuterFadeDownLen, duckRegionEnd + mOuterFadeUpLen)); inDuckRegion = false; } } } pos += len; if (TotalProgress( (pos - start).as_double() / (end - start).as_double() / (GetNumWaveTracks() + 1) )) { cancel = true; break; } } // apply last duck fade, if any if (inDuckRegion) { double duckRegionEnd = mControlTrack->LongSamplesToTime(end - curSamplesPause); regions.push_back(AutoDuckRegion( duckRegionStart - mOuterFadeDownLen, duckRegionEnd + mOuterFadeUpLen)); } } if (!cancel) { CopyInputTracks(); // Set up mOutputTracks. SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks.get()); Track *iterTrack = iter.First(); int trackNum = 0; while (iterTrack) { WaveTrack* t = (WaveTrack*)iterTrack; for (size_t i = 0; i < regions.size(); i++) { const AutoDuckRegion& region = regions[i]; if (ApplyDuckFade(trackNum, t, region.t0, region.t1)) { cancel = true; break; } } if (cancel) break; iterTrack = iter.Next(); trackNum++; } } ReplaceProcessedTracks(!cancel); return !cancel; }
void SearchImageThread::run() { HANDLE hFile = CreateFile( m_imageFile.c_str(), FILE_GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if ( INVALID_HANDLE_VALUE == hFile ) { return; } LARGE_INTEGER fs = {0}; GetFileSizeEx(hFile, &fs); LONGLONG fileSize = fs.QuadPart; DWORD readPieceSize = BufferSize; LONGLONG currentProcess = 0; DWORD readed = 0; emit TotalProgress(100); unsigned char* buffer = new unsigned char[readPieceSize]; QByteArray searchStr = m_utf8 ? m_searchStr.toUtf8() : m_searchStr.toLocal8Bit(); int patternLen = searchStr.length(); unsigned char* pattern = new unsigned char[patternLen]; memcpy(pattern, searchStr.data(), patternLen); while (true) { memset(buffer, 0, readPieceSize); ReadFile(hFile, buffer, readPieceSize, &readed, NULL); // Search buffer char displayText[ContentSize+1] = {0}; for ( int i = 0; i < readPieceSize; ) { if ( 0 == memcmp(buffer+i, pattern, patternLen) ) { for ( int j = 0; j < ContentSize; ++j ) { if ( buffer[i+j] == 0 ) displayText[j] = ' '; else displayText[j] = buffer[i+j]; } QString result = m_utf8 ? QString::fromUtf8(displayText, ContentSize+1) : QString::fromLocal8Bit(displayText, ContentSize+1); emit SearchResult(result, currentProcess + i); i += ContentSize; } else ++i; } currentProcess += readed; emit CurrentProgress((int)(currentProcess * 100 / fileSize)); if ( 0 == readed ) break; } delete [] buffer; CloseHandle(hFile); }