⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmixerthread.cpp

📁 在symbian中
💻 CPP
字号:
/*
 * ============================================================================
 *  Name     : CMixerThread.cpp
 *  Part of  : SoundMixer
 *  Created  : 03/30/2006 by Forum Nokia
 *  Description:
 *     This is the project specification file for SoundMixer.
 *  Version  : 2.0.0
 *  Copyright: Forum Nokia
 * ============================================================================
 */

// INCLUDES

#include "CMixerThread.h"
#include <e32svr.h>
#include "TSample.h"
#include "TAudioShared.h"
#include "MyActive.h"
#include "SoundMixer.pan"

// CONSTANTS
const TInt KSampleRate = 16000;                 // sample rate used
const TInt KBufferSize = KSampleRate / 20;      // 20 buffers per second


TInt CMixerThread::ThreadFunction( TAny* aData )
  {
  TAudioShared& shared = *((TAudioShared*)aData);

  // tell client we're alive
  // signaled off when destroying this thread
  shared.iAliveMutex.Wait();
  CMixerThread* mixerThread = NULL;
  
  TRAPD(error, mixerThread = CMixerThread::CreateL( aData ));
  if(error!=KErrNone)
    {
    return error;
    }
  
  if( mixerThread == NULL )
    {
    return KErrGeneral;
    }

  shared.iStatusPtr = &(mixerThread->iActive->iStatus);

  // if we're still here, activescheduler has been constructed
  // start wait loop which runs until it's time to end the thread
  CActiveScheduler::Start();
  delete mixerThread;

  // tell owning thread it's safe to exit
  shared.iAliveMutex.Signal();

  return KErrNone;
  }


CMixerThread* CMixerThread::CreateL( TAny* aData )
  {
  CMixerThread* self = new( ELeave )CMixerThread( aData );
  if( self == NULL ) return self;
  if( self->Construct() != KErrNone )
    {
    delete self;
    return NULL;
    }

  return self;
  }


TInt CMixerThread::Construct()
  {
  // create cleanup stack
  iCleanupStack = CTrapCleanup::New();
  if( iCleanupStack == NULL )
    {
    return KErrNoMemory;
    }

  TInt err = KErrNone;
  TRAP( err, ConstructL() );
  return err;
  }


void CMixerThread::ConstructL()
  {
  // create active scheduler
  iActiveScheduler = new( ELeave )CActiveScheduler;
  CActiveScheduler::Install( iActiveScheduler );

  // sound inits
  iSet.iChannels = TMdaAudioDataSettings::EChannelsMono;
  iSet.iSampleRate = TMdaAudioDataSettings::ESampleRate16000Hz;
  iSet.iVolume = 1;

  iMixBuffer = new( ELeave )TInt[ KBufferSize ];
  iBuffer = new( ELeave )TInt16[ KBufferSize ];

  iBufferPtr.Set( TPtrC8( (TUint8*)iBuffer, KBufferSize*2 ) );

  iActive = new(ELeave) MyActive(this);
  iActive->Request();
  }


CMixerThread::CMixerThread( TAny* aData )
  : iShared( *((TAudioShared*)aData))
  {
  }


CMixerThread::~CMixerThread()
  {
  delete iStream;
  delete iBuffer;
  delete iMixBuffer;
  delete iActiveScheduler;
  delete iCleanupStack;
  if(iActive)
    {
    iActive->Cancel();  
    }
  delete iActive;
  }


void CMixerThread::HandleExceptionL()
  {
  // handle exceptions
  
  // Note: After adding support for 3rd Ed, there is no longer actual
  // thread exception handling - instead, inter-thread communication is done 
  // via active object/scheduler. This function is now called from MyActive.
  
  switch( iShared.iExc )
    {
    case EExcUserInterrupt:       // Command from client
      {
      switch( iShared.iCmd )
        {
        case ECmdStartMixer:
          {
          StartMixerL();
          break;
          }
        case ECmdStopMixer:
          {
          StopMixer();
          break;
          }
        case ECmdDestroyMixer:
          {
          CActiveScheduler::Stop();   // Exit
          break;
          }
        }
      break;
      }
    default:
      {
      // if unknown exception, just exit this thread
      CActiveScheduler::Stop();       // Exit
      break;
      }
    }
  }


void CMixerThread::StartMixerL()
  {
  iStream = CMdaAudioOutputStream::NewL( *this );
  iStream->Open( &iSet );
  }


void CMixerThread::StopMixer()
  {
  iStream->Stop();
  delete iStream;
  iStream = NULL;
  }


void CMixerThread::FillBufferL()
  {
  // wait for access to shared data
  iShared.iMutex.Wait();

  TInt volume = iShared.iMainVolume;

  // Gather new sample information
  TInt i;
  for( i=0; i<KMaxChannels; i++ )
    {
    if( iShared.iPlayStarted[ i ] )
      {
      iShared.iPlayStarted[ i ] = EFalse;
      TSample& s = iShared.iSample[ i ];

      iAudioData[ i ] = s.iData;
      iAudioPos[ i ] = 0;
      iAudioEnd[ i ] = s.iLength << KAudioShift;
      iRepStart[ i ] = s.iRepStart << KAudioShift;
      iRepEnd[ i ] = s.iRepEnd << KAudioShift;
      }
    }
  // give access to shared data
  iShared.iMutex.Signal();

  // clear buffer
  // has to be done because channels are mixed by adding their values
  // to each other
  Mem::FillZ( iMixBuffer, KBufferSize*4 );

  // mix active channels
  for( i=0; i<KMaxChannels; i++ )
    {
    if( iAudioData[ i ] != NULL )
      {
      TInt* buf = iMixBuffer;
      TInt* bufEnd = buf + KBufferSize;

      TInt16* src = iAudioData[ i ];

      TInt pos = iAudioPos[ i ];
      TInt posEnd = iAudioEnd[ i ];
      TInt repStart = iRepStart[ i ];
      TInt repEnd = iRepEnd[ i ];
      TInt posAdd = ( iShared.iFrequency[ i ] << KAudioShift ) / KSampleRate;
      TInt volume = iShared.iVolume[ i ];

      while( buf < bufEnd )
        {
        TInt sample = ( src[ pos >> KAudioShift ] * volume );
        pos += posAdd;
        if( pos >= posEnd )
          {
          if( repEnd == 0 )
            {
            iAudioData[ i ] = NULL;
            break;
            }
          else
            {
            pos = repStart;
            posEnd = repEnd;
            }
          }
        *buf++ += sample;
        }
      iAudioPos[ i ] = pos;
      iAudioEnd[ i ] = posEnd;
      }
    }

  // convert 32-bit mixing buffer to 16-bit output buffer
  TInt* buf = iMixBuffer;
  TInt* bufEnd = buf + KBufferSize;
  TInt16* buf2 = iBuffer;
  while( buf < bufEnd )
    {
    // 32-bit mixer buffer contents are multiplied by main volume
    // shifts are in two phases to prevent overflow and maintain quality
    TInt value = ( ( *buf++ >> 8 ) * volume ) >> 8;

    // Prevent sound from trashing on overboost volume:
    if( value < -0x7fff ) value = -0x7fff;
    if( value > 0x7fff ) value = 0x7fff;

    // and write to buffer
    *buf2++ = (TInt16)value;
    }

  // write 16-bit buffer to CMdaAudioOutputStream
  iStream->WriteL( iBufferPtr );
  }


void CMixerThread::MaoscBufferCopied( TInt aError, const TDesC8& /*aBuffer*/ )
  {
  if( aError )
    {
    iError = aError;
    }
  else
    {
    TRAPD(error, FillBufferL());
    PanicIfError(error);
    }
  }


void CMixerThread::MaoscOpenComplete( TInt aError )
  {
  if( aError )
    {
    iError = aError;
    }
  else
    {
    iStream->SetVolume( iStream->MaxVolume() );
    TRAPD(error, FillBufferL());
    PanicIfError(error);
    }
  }


void CMixerThread::MaoscPlayComplete( TInt aError )
  {
  if( aError )
    {
    iError = aError;
    }
  else
    {
    iStream->SetVolume( iStream->MaxVolume() );
    TRAPD(error, FillBufferL());
    PanicIfError(error);
    }
  }

// End of File

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -