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

📄 cmixerthread.cpp

📁 手机游戏:Symbian S60俄罗斯方块(Tetris)的源代码
💻 CPP
字号:
// INCLUDES
#include "CMixerThread.h"
#include <e32svr.h>
#include "TSample.h"
#include "TAudioShared.h"

// 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 = CMixerThread::Create( aData );
	if( mixerThread == NULL )
	{
		return KErrGeneral;
	}

	// 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::Create( TAny* aData )
{
	CMixerThread* self = new 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 ) );

	// store pointer of this class to thread local store
	// for use in ExcHandler ( static function )
	Dll::SetTls( this );
	RThread().SetExceptionHandler( ExcHandler, 0xffffffff );
}

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

CMixerThread::~CMixerThread()
{
	delete iStream;
	delete iBuffer;
	delete iMixBuffer;

	delete iActiveScheduler;
	delete iCleanupStack;
}

void CMixerThread::ExcHandler( TExcType aExc )
{
	// exception handler entry function
	CMixerThread* mixerPointer = (CMixerThread*)Dll::Tls();
	mixerPointer->HandleException( aExc );
}

void CMixerThread::HandleException( TExcType aExc )
{
	// handle exceptions
	// exception type EExcUserInterrupt is reserved for inter-thread communication
	switch( aExc )
	{
		case EExcUserInterrupt:				// Command from client
		{
			switch( iShared.iCmd )
			{
				case ECmdStartMixer:
				{
					StartMixer();		
				}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::StartMixer()
{
	iStream = CMdaAudioOutputStream::NewL( *this );
	iStream->Open( &iSet );
}


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

void CMixerThread::FillBuffer()
{
	// 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
	{
		FillBuffer();
	}
}

void CMixerThread::MaoscOpenComplete( TInt aError )
{
	if( aError )
	{
		iError = aError;
	}
	else
	{
		iStream->SetVolume( iStream->MaxVolume() );
		FillBuffer();
	}
}

void CMixerThread::MaoscPlayComplete( TInt aError )
{
	if( aError )
	{
		iError = aError;
	}
	else
	{
		iStream->SetVolume( iStream->MaxVolume() );
		FillBuffer();
	}
}




⌨️ 快捷键说明

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