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

📄 cmixerthread.cpp

📁 SoundMixer example application is compatible with Series 60 Developer Platform v1.0 and v2.0. It
💻 CPP
字号:
   /*
    *
============================================================================
    *  Name     : CMixerThread.cpp
    *  Part of  : SoundMixer
    *  Created  : 03/01/2003 by Forum Nokia
    *  Description:
    *     This is the project specification file for SoundMixer.
    *
    *  Version  : 1.0.0
    *  Copyright: Forum Nokia
    *
============================================================================
    */

// 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 + -