mirror of
				https://github.com/cookiengineer/audacity
				synced 2025-11-03 23:53:55 +01:00 
			
		
		
		
	Bug 1336 - Tracks -> Mix Stereo to Mono ignores envelope
This commit is contained in:
		@@ -19,7 +19,9 @@
 | 
			
		||||
 | 
			
		||||
#include <wx/intl.h>
 | 
			
		||||
 | 
			
		||||
#include "../Mix.h"
 | 
			
		||||
#include "../Project.h"
 | 
			
		||||
#include "../TimeTrack.h"
 | 
			
		||||
#include "../WaveTrack.h"
 | 
			
		||||
 | 
			
		||||
const ComponentInterfaceSymbol EffectStereoToMono::Symbol
 | 
			
		||||
@@ -81,89 +83,125 @@ bool EffectStereoToMono::Process()
 | 
			
		||||
   this->CopyInputTracks(); // Set up mOutputTracks.
 | 
			
		||||
   bool bGoodResult = true;
 | 
			
		||||
 | 
			
		||||
   // Determine the total time (in samples) used by all of the target tracks
 | 
			
		||||
   sampleCount totalTime = 0;
 | 
			
		||||
   
 | 
			
		||||
   auto trackRange = mOutputTracks->SelectedLeaders< WaveTrack >();
 | 
			
		||||
   while (trackRange.first != trackRange.second)
 | 
			
		||||
   {
 | 
			
		||||
      auto left = *trackRange.first;
 | 
			
		||||
      auto channels = TrackList::Channels(left);
 | 
			
		||||
      if (channels.size() > 1)
 | 
			
		||||
      {
 | 
			
		||||
         auto right = *channels.rbegin();
 | 
			
		||||
         if (left->GetRate() == right->GetRate())
 | 
			
		||||
         {
 | 
			
		||||
            auto start = wxMin(left->TimeToLongSamples(left->GetStartTime()),
 | 
			
		||||
                               right->TimeToLongSamples(right->GetStartTime()));
 | 
			
		||||
            auto end = wxMin(left->TimeToLongSamples(left->GetEndTime()),
 | 
			
		||||
                               right->TimeToLongSamples(right->GetEndTime()));
 | 
			
		||||
 | 
			
		||||
            totalTime += (end - start);
 | 
			
		||||
         }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      ++trackRange.first;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   // Process each stereo track
 | 
			
		||||
   sampleCount curTime = 0;
 | 
			
		||||
   bool refreshIter = false;
 | 
			
		||||
 | 
			
		||||
   int count = 0;
 | 
			
		||||
   while ( trackRange.first != trackRange.second ) {
 | 
			
		||||
      mLeftTrack = *trackRange.first;
 | 
			
		||||
      auto channels = TrackList::Channels( mLeftTrack );
 | 
			
		||||
      if (channels.size() != 2) {
 | 
			
		||||
         // TODO: more-than-two-channels
 | 
			
		||||
         ++ trackRange.first;
 | 
			
		||||
         continue;
 | 
			
		||||
   trackRange = mOutputTracks->SelectedLeaders< WaveTrack >();
 | 
			
		||||
   while (trackRange.first != trackRange.second)
 | 
			
		||||
   {
 | 
			
		||||
      auto left = *trackRange.first;
 | 
			
		||||
      auto channels = TrackList::Channels(left);
 | 
			
		||||
      if (channels.size() > 1)
 | 
			
		||||
      {
 | 
			
		||||
         auto right = *channels.rbegin();
 | 
			
		||||
 | 
			
		||||
         if (left->GetRate() == right->GetRate())
 | 
			
		||||
         {
 | 
			
		||||
            bGoodResult = ProcessOne(curTime, totalTime, left, right);
 | 
			
		||||
            if (!bGoodResult)
 | 
			
		||||
            {
 | 
			
		||||
               break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // The right channel has been deleted, so we must restart from the beginning
 | 
			
		||||
            refreshIter = true;
 | 
			
		||||
         }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      mRightTrack = * channels.rbegin();
 | 
			
		||||
 | 
			
		||||
      if ((mLeftTrack->GetRate() == mRightTrack->GetRate())) {
 | 
			
		||||
         auto leftTrackStart = mLeftTrack->TimeToLongSamples(mLeftTrack->GetStartTime());
 | 
			
		||||
         auto rightTrackStart = mRightTrack->TimeToLongSamples(mRightTrack->GetStartTime());
 | 
			
		||||
         mStart = wxMin(leftTrackStart, rightTrackStart);
 | 
			
		||||
 | 
			
		||||
         auto leftTrackEnd = mLeftTrack->TimeToLongSamples(mLeftTrack->GetEndTime());
 | 
			
		||||
         auto rightTrackEnd = mRightTrack->TimeToLongSamples(mRightTrack->GetEndTime());
 | 
			
		||||
         mEnd = wxMax(leftTrackEnd, rightTrackEnd);
 | 
			
		||||
 | 
			
		||||
         bGoodResult = ProcessOne(count);
 | 
			
		||||
         if (!bGoodResult)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
         // The right channel has been deleted, so we must restart from the beginning
 | 
			
		||||
         refreshIter = true;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (refreshIter) {
 | 
			
		||||
      if (refreshIter)
 | 
			
		||||
      {
 | 
			
		||||
         trackRange = mOutputTracks->SelectedLeaders< WaveTrack >();
 | 
			
		||||
         refreshIter = false;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
         ++trackRange.first;
 | 
			
		||||
 | 
			
		||||
      count++;
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   this->ReplaceProcessedTracks(bGoodResult);
 | 
			
		||||
   return bGoodResult;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool EffectStereoToMono::ProcessOne(int count)
 | 
			
		||||
bool EffectStereoToMono::ProcessOne(sampleCount & curTime, sampleCount totalTime, WaveTrack *left, WaveTrack *right)
 | 
			
		||||
{
 | 
			
		||||
   float  curLeftFrame;
 | 
			
		||||
   float  curRightFrame;
 | 
			
		||||
   float  curMonoFrame;
 | 
			
		||||
 | 
			
		||||
   auto idealBlockLen = mLeftTrack->GetMaxBlockSize() * 2;
 | 
			
		||||
   auto index = mStart;
 | 
			
		||||
   Floats leftBuffer { idealBlockLen };
 | 
			
		||||
   Floats rightBuffer{ idealBlockLen };
 | 
			
		||||
   auto idealBlockLen = left->GetMaxBlockSize() * 2;
 | 
			
		||||
   bool bResult = true;
 | 
			
		||||
   sampleCount processed = 0;
 | 
			
		||||
 | 
			
		||||
   auto outTrack = mLeftTrack->EmptyCopy();
 | 
			
		||||
   outTrack->ConvertToSampleFormat( floatSample );
 | 
			
		||||
   auto start = wxMin(left->TimeToLongSamples(left->GetStartTime()),
 | 
			
		||||
                      right->TimeToLongSamples(right->GetStartTime()));
 | 
			
		||||
   auto end = wxMin(left->TimeToLongSamples(left->GetEndTime()),
 | 
			
		||||
                    right->TimeToLongSamples(right->GetEndTime()));
 | 
			
		||||
 | 
			
		||||
   while (index < mEnd) {
 | 
			
		||||
      bResult &= mLeftTrack->Get((samplePtr)leftBuffer.get(), floatSample, index, idealBlockLen);
 | 
			
		||||
      bResult &= mRightTrack->Get((samplePtr)rightBuffer.get(), floatSample, index, idealBlockLen);
 | 
			
		||||
      auto limit = limitSampleBufferSize( idealBlockLen, mEnd - index );
 | 
			
		||||
      for (decltype(limit) i = 0; i < limit; ++i) {
 | 
			
		||||
         index++;
 | 
			
		||||
         curLeftFrame = leftBuffer[i];
 | 
			
		||||
         curRightFrame = rightBuffer[i];
 | 
			
		||||
         curMonoFrame = (curLeftFrame + curRightFrame) / 2.0;
 | 
			
		||||
         leftBuffer[i] = curMonoFrame;
 | 
			
		||||
   WaveTrackConstArray tracks;
 | 
			
		||||
   tracks.push_back(left->SharedPointer< const WaveTrack >());
 | 
			
		||||
   tracks.push_back(right->SharedPointer< const WaveTrack >());
 | 
			
		||||
 | 
			
		||||
   auto timeTrack = *(inputTracks()->Any<const TimeTrack>().begin());
 | 
			
		||||
 | 
			
		||||
   Mixer mixer(tracks,
 | 
			
		||||
               true,                // Throw to abort mix-and-render if read fails:
 | 
			
		||||
               Mixer::WarpOptions(timeTrack ? timeTrack->GetEnvelope() : nullptr),
 | 
			
		||||
               start.as_double(),
 | 
			
		||||
               end.as_double(),
 | 
			
		||||
               1,
 | 
			
		||||
               idealBlockLen,
 | 
			
		||||
               false,               // Not interleaved
 | 
			
		||||
               mProjectRate,
 | 
			
		||||
               floatSample);
 | 
			
		||||
 | 
			
		||||
   auto outTrack = left->EmptyCopy();
 | 
			
		||||
   outTrack->ConvertToSampleFormat(floatSample);
 | 
			
		||||
 | 
			
		||||
   while (auto blockLen = mixer.Process(idealBlockLen))
 | 
			
		||||
   {
 | 
			
		||||
      auto buffer = mixer.GetBuffer();
 | 
			
		||||
      for (auto i = 0; i < blockLen; i++)
 | 
			
		||||
      {
 | 
			
		||||
         ((float *)buffer)[i] /= 2.0;
 | 
			
		||||
      }
 | 
			
		||||
      outTrack->Append((samplePtr)leftBuffer.get(), floatSample, limit);
 | 
			
		||||
      if (TrackProgress(count, 2.*(index.as_double() / (mEnd - mStart).as_double())))
 | 
			
		||||
         return false;
 | 
			
		||||
   }
 | 
			
		||||
      outTrack->Append(buffer, floatSample, blockLen);
 | 
			
		||||
 | 
			
		||||
   double minStart = wxMin(mLeftTrack->GetStartTime(), mRightTrack->GetStartTime());
 | 
			
		||||
   mLeftTrack->Clear(mLeftTrack->GetStartTime(), mLeftTrack->GetEndTime());
 | 
			
		||||
      curTime += blockLen;
 | 
			
		||||
      if (TotalProgress(curTime.as_double() / totalTime.as_double()))
 | 
			
		||||
      {
 | 
			
		||||
         return false;
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
   outTrack->Flush();
 | 
			
		||||
   mLeftTrack->Paste(minStart, outTrack.get());
 | 
			
		||||
   mOutputTracks->GroupChannels( *mLeftTrack,  1 );
 | 
			
		||||
   mOutputTracks->Remove(mRightTrack);
 | 
			
		||||
 | 
			
		||||
   double minStart = wxMin(left->GetStartTime(), right->GetStartTime());
 | 
			
		||||
   left->Clear(left->GetStartTime(), left->GetEndTime());
 | 
			
		||||
   left->Paste(minStart, outTrack.get());
 | 
			
		||||
   mOutputTracks->GroupChannels(*left,  1);
 | 
			
		||||
   mOutputTracks->Remove(right);
 | 
			
		||||
 | 
			
		||||
   return bResult;
 | 
			
		||||
}
 | 
			
		||||
@@ -172,4 +210,3 @@ bool EffectStereoToMono::IsHidden()
 | 
			
		||||
{
 | 
			
		||||
   return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -44,13 +44,8 @@ public:
 | 
			
		||||
private:
 | 
			
		||||
   // EffectStereoToMono implementation
 | 
			
		||||
 | 
			
		||||
   bool ProcessOne(int count);
 | 
			
		||||
   bool ProcessOne(sampleCount & curTime, sampleCount totalTime, WaveTrack *left, WaveTrack *right);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
   sampleCount mStart;
 | 
			
		||||
   sampleCount mEnd;
 | 
			
		||||
   WaveTrack *mLeftTrack;
 | 
			
		||||
   WaveTrack *mRightTrack;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user