mmlibs/mmfw/MIDI/src/midiclientutilitybody.cpp
changeset 0 40261b775718
child 31 ae0addfe117e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmlibs/mmfw/MIDI/src/midiclientutilitybody.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,1110 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "midiclientutilitybody.h"
+
+const TInt KMimeLength         = 256;
+const TInt KMinChannel         = 0;
+const TInt KMaxChannel         = 15;
+const TInt KMinNote            = 0;
+const TInt KMaxNote            = 127;
+const TInt KMinNoteOnVelocity  = 0;
+const TInt KMaxNoteOnVelocity  = 127;
+const TInt KMinNoteOffVelocity = 0;
+const TInt KMaxNoteOffVelocity = 127;
+const TInt KMinInstrumentId    = 0;
+const TInt KMaxInstrumentId    = 127;
+
+
+CMidiClientUtility::CBody* CMidiClientUtility::CBody::NewL(CMidiClientUtility* aParent,
+														   MMidiClientUtilityObserver& aObserver, 
+														   TInt aPriority, 
+														   TInt aPref,
+														   TBool aUseSharedHeap)
+	{
+	CBody* self = new(ELeave) CBody(aParent, aObserver, aPriority, aPref);
+	CleanupStack::PushL(self);
+	self->ConstructL(aUseSharedHeap);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CMidiClientUtility::CBody::CBody(CMidiClientUtility* aParent, 
+								 MMidiClientUtilityObserver& aObserver, 
+								 TInt aPriority, 
+								 TInt aPref) :
+	iObserver(aObserver),
+	iMidiControllerCommands(iController),
+	iDRMCustomCommands(iController)
+
+	{
+	iParent = aParent;
+	iState = EMidiStateClosedDisengaged;
+	iPrioritySettings.iPriority = aPriority;
+	iPrioritySettings.iPref = aPref;
+	iIntervalSec = ETrue;
+	iStopPosition = TTimeIntervalMicroSeconds(0);
+	}
+
+CMidiClientUtility::CBody::~CBody()
+	{
+	delete iAddDataSourceSinkAsync;
+	if (iMidiControllerEventMonitor)
+		iMidiControllerEventMonitor->Cancel();
+		
+	iController.Close();
+	delete iMidiControllerEventMonitor;
+	delete iMimeType;
+	delete iRepeatTrailingSilenceTimer;
+	delete iSource;
+	}
+
+void CMidiClientUtility::CBody::ConstructL(TBool aUseSharedHeap)
+	{
+	iMidiControllerEventMonitor = CMidiControllerEventMonitor::NewL(*this, iMidiControllerCommands, *iParent);
+	iMimeType = HBufC8::NewL(KMimeLength);
+		
+	RMMFControllerImplInfoArray controllers;
+	CleanupResetAndDestroyPushL(controllers);
+	CMMFControllerPluginSelectionParameters* cSelect = CMMFControllerPluginSelectionParameters::NewLC();
+
+	// Select the media IDs to allow
+	RArray<TUid> mediaIds;
+	CleanupClosePushL(mediaIds);
+	User::LeaveIfError(mediaIds.Append(KUidMediaTypeMidi));
+	cSelect->SetMediaIdsL(mediaIds,CMMFPluginSelectionParameters::EAllowOnlySuppliedMediaIds);
+	CleanupStack::PopAndDestroy();//mediaIds
+	cSelect->ListImplementationsL(controllers);
+	// Open and configure a controller
+	User::LeaveIfError(DoOpen(controllers, KUidMmfAudioOutput, KNullDesC8, aUseSharedHeap));
+	CleanupStack::PopAndDestroy(2);//controllers, cSelect
+	iRepeatTrailingSilenceTimer = CRepeatTrailingSilenceTimer::NewL(*this);
+	iAddDataSourceSinkAsync = CMMFAddDataSourceSinkAsync::NewL(*this);
+	}
+
+void CMidiClientUtility::CBody::MadssaoAddDataSourceSinkAsyncComplete(TInt aError, const TMMFMessageDestination& aHandle)
+	{
+	if (aError == KErrNone)
+		{
+		iSourceHandle = aHandle;
+		}
+	else
+		{
+ 		iMidiControllerEventMonitor->SelfComplete(aError);
+		}
+	}
+void CMidiClientUtility::CBody::OpenFile(const TDesC& aFileName)
+	{
+	TMMFFileConfig sourceCfg;
+	sourceCfg().iPath = aFileName;
+	// Add the data source to the controller. MmcuoStateChanged will be call on completition.
+	iAddDataSourceSinkAsync->AddDataSource(iController, KUidMmfFileSource, sourceCfg);
+	}
+
+void CMidiClientUtility::CBody::OpenFile(RFile& aFile)
+	{
+		// Add the data source to the controller. MmcuoStateChanged will be call on completition.
+	iAddDataSourceSinkAsync->AddFileHandleDataSource(iController, aFile);
+	}
+
+void CMidiClientUtility::CBody::OpenFile(const TMMSource& aSource)
+	{
+	TRAPD(err, DoOpenFileL(aSource));
+	if (err != KErrNone)
+		{
+ 		iMidiControllerEventMonitor->SelfComplete(err);
+		}
+	}
+	
+	
+void CMidiClientUtility::CBody::DoOpenFileL(const TMMSource& aSource)
+	{
+	delete iSource;
+	iSource = NULL;
+	iSource = CMMFileSourceSink::NewL(KUidMmfFileSource, aSource);
+	static_cast<CMMFileSourceSink*>(iSource)->EvaluateIntentL( aSource.Intent() );
+	iAddDataSourceSinkAsync->AddDataSource(iController, 
+								iSource->SourceSinkUid(),
+								iSource->SourceSinkData());
+	}
+
+void CMidiClientUtility::CBody::OpenDes(const TDesC8& aDescriptor)
+	{
+	TMMFDescriptorConfig sourceCfg;
+	sourceCfg().iDes = (TAny*)&aDescriptor;
+	sourceCfg().iDesThreadId = RThread().Id();
+	// Add the data source to the controller. MmcuoStateChanged will be call on completition.
+	iAddDataSourceSinkAsync->AddDataSource(iController, KUidMmfDescriptorSource, sourceCfg);
+	}
+
+void CMidiClientUtility::CBody::OpenUrl(const TDesC& aUrl,TInt aIapId,const TDesC8& /*aMimeType*/)
+	{
+	TRAPD(err, DoOpenUrlL(aUrl, aIapId));
+
+	if (err != KErrNone)
+		{
+ 		iMidiControllerEventMonitor->SelfComplete(err);
+		}
+
+	}
+
+void CMidiClientUtility::CBody::DoOpenUrlL(const TDesC& aUrl,TInt aIapId)
+	{
+	CMMFUrlParams* sourceCfg = CMMFUrlParams::NewLC(aUrl, aIapId);
+	CBufFlat* sourceCfgBuffer = sourceCfg->ExternalizeToCBufFlatLC();
+	// Add the data source to the controller. MmcuoStateChanged will be call on completition.
+	iAddDataSourceSinkAsync->AddDataSource(iController, KUidMmfUrlSource, sourceCfgBuffer->Ptr(0));
+	CleanupStack::PopAndDestroy(2, sourceCfg);//sourceCfgBuffer, sourceCfg
+	}
+
+void CMidiClientUtility::CBody::Close()
+	{
+	iMidiControllerCommands.Close();
+	}
+
+void CMidiClientUtility::CBody::Play()
+	{
+	TInt err = iController.Prime();
+	if (err==KErrNone)
+		{
+		err=iController.Play();
+		}
+	if (err!=KErrNone)
+		{
+		iMidiControllerEventMonitor->SelfComplete(err);
+		}
+	}
+
+void CMidiClientUtility::CBody::Stop(const TTimeIntervalMicroSeconds& aFadeOutDuration)
+	{
+	iMidiControllerCommands.Stop(aFadeOutDuration);
+	}
+	
+/**
+ *
+ * Returns the current state of the MIDI client utility
+ * with regard to MIDI resources.
+ *
+ * @return "TMidiState" The current state of the utility
+ *
+ * @since	7.0s
+ */
+
+TMidiState CMidiClientUtility::CBody::State() const
+	{
+	return iState;
+	}
+
+void CMidiClientUtility::CBody::PlayNoteL(TInt aChannel,TInt aNote,const TTimeIntervalMicroSeconds& aDuration,TInt aNoteOnVelocity,TInt aNoteOffVelocity)
+	{
+	if((aChannel >= KMinChannel && aChannel <= KMaxChannel) 
+	&& (aNote >= KMinNote && aNote <= KMaxNote) 
+	&& (aNoteOnVelocity >= KMinNoteOnVelocity && aNoteOnVelocity <= KMaxNoteOnVelocity) 
+	&& (aNoteOffVelocity >= KMinNoteOffVelocity && aNoteOffVelocity <= KMaxNoteOffVelocity))
+		{	
+		User::LeaveIfError(iMidiControllerCommands.PlayNote(aChannel, aNote, aDuration, aNoteOnVelocity, aNoteOffVelocity));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+void CMidiClientUtility::CBody::PlayNoteL(TInt aChannel,TInt aNote, const TTimeIntervalMicroSeconds& aStartTime, const TTimeIntervalMicroSeconds& aDuration, TInt aNoteOnVelocity, TInt aNoteOffVelocity)
+	{
+	if((aChannel >= KMinChannel && aChannel <= KMaxChannel) 
+	&& (aNote >= KMinNote && aNote <= KMaxNote) 
+	&& (aNoteOnVelocity >= KMinNoteOnVelocity && aNoteOnVelocity <= KMaxNoteOnVelocity) 
+	&& (aNoteOffVelocity >= KMinNoteOffVelocity && aNoteOffVelocity <= KMaxNoteOffVelocity))
+		{
+		User::LeaveIfError(iMidiControllerCommands.PlayNote(aChannel, aNote, aStartTime, aDuration, aNoteOnVelocity, aNoteOffVelocity));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+void CMidiClientUtility::CBody::StopNotes(TInt aChannel)
+	{
+	if(aChannel >= KMinChannel && aChannel <= KMaxChannel) 
+		{
+		iMidiControllerCommands.StopNotes(aChannel);
+		}
+	}
+
+void CMidiClientUtility::CBody::NoteOnL(TInt aChannel,TInt aNote,TInt aVelocity)
+	{
+	if((aChannel >= KMinChannel && aChannel <= KMaxChannel) 
+	&& (aNote >= KMinNote && aNote <= KMaxNote) 
+	&& (aVelocity >= KMinNoteOnVelocity && aVelocity <= KMaxNoteOnVelocity))
+		{
+		User::LeaveIfError(iMidiControllerCommands.NoteOn(aChannel, aNote, aVelocity));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+void CMidiClientUtility::CBody::NoteOffL(TInt aChannel,TInt aNote,TInt aVelocity)
+	{
+	if((aChannel >= KMinChannel && aChannel <= KMaxChannel) 
+	&& (aNote >= KMinNote && aNote <= KMaxNote) 
+	&& (aVelocity >= KMinNoteOffVelocity && aVelocity <= KMaxNoteOffVelocity))
+		{
+		User::LeaveIfError(iMidiControllerCommands.NoteOff(aChannel, aNote, aVelocity));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+TInt CMidiClientUtility::CBody::PlaybackRateL() const
+	{
+	TInt rate;
+	User::LeaveIfError(iMidiControllerCommands.PlaybackRate(rate));
+	return rate;
+	}
+
+void CMidiClientUtility::CBody::SetPlaybackRateL(TInt aRate)
+	{
+	User::LeaveIfError(iMidiControllerCommands.SetPlaybackRate(aRate));
+	}
+
+TInt CMidiClientUtility::CBody::MaxPlaybackRateL() const
+	{
+	TInt maxRate;
+	User::LeaveIfError(iMidiControllerCommands.MaxPlaybackRate(maxRate));
+	return maxRate;
+	}
+
+TInt CMidiClientUtility::CBody::MinPlaybackRateL() const
+	{
+	TInt minRate;
+	User::LeaveIfError(iMidiControllerCommands.MinPlaybackRate(minRate));
+	return minRate;
+	}
+
+
+TInt CMidiClientUtility::CBody::TempoMicroBeatsPerMinuteL() const
+	{
+	TInt microBeatsPerMinute;
+	User::LeaveIfError(iMidiControllerCommands.TempoMicroBeatsPerMinute(microBeatsPerMinute));
+	return microBeatsPerMinute;
+	}
+
+void CMidiClientUtility::CBody::SetTempoL(TInt aMicroBeatsPerMinute)
+	{
+	if(aMicroBeatsPerMinute > 0)
+		{
+		User::LeaveIfError(iMidiControllerCommands.SetTempo(aMicroBeatsPerMinute));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+TInt CMidiClientUtility::CBody::PitchTranspositionCentsL() const
+	{
+	TInt cents;
+	User::LeaveIfError(iMidiControllerCommands.PitchTranspositionCents(cents));
+	return cents;
+	}
+
+TInt CMidiClientUtility::CBody::SetPitchTranspositionL(TInt aCents)
+	{
+	TInt pitchApplied = 0;
+	//we do not check aCents value - it is expected the controller will report KErrArgument
+	//if the pitch level is not supported.
+	User::LeaveIfError(iMidiControllerCommands.SetPitchTransposition(aCents, pitchApplied));
+
+	return pitchApplied;
+	}
+
+TTimeIntervalMicroSeconds CMidiClientUtility::CBody::DurationMicroSecondsL() const
+	{
+	TTimeIntervalMicroSeconds duration;
+	User::LeaveIfError(iController.GetDuration(duration));
+	return duration;
+	}
+
+TInt64 CMidiClientUtility::CBody::DurationMicroBeatsL() const
+	{
+	TInt64 duration;
+	User::LeaveIfError(iMidiControllerCommands.DurationMicroBeats(duration));
+	return duration;
+	}
+
+TInt CMidiClientUtility::CBody::NumTracksL() const
+	{
+	TInt tracks;
+	User::LeaveIfError(iMidiControllerCommands.NumTracks(tracks));
+	return tracks;
+	}
+
+void CMidiClientUtility::CBody::SetTrackMuteL(TInt aTrack, TBool aMuted) const
+	{
+	TInt numTracks = NumTracksL();
+	if((aTrack >= 0) && (aTrack < numTracks))
+		{
+		User::LeaveIfError(iMidiControllerCommands.SetTrackMute(aTrack, aMuted));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+const TDesC8& CMidiClientUtility::CBody::MimeTypeL()
+	{
+	TPtr8 des = iMimeType->Des();
+	User::LeaveIfError(iMidiControllerCommands.MimeType(des));
+	return *iMimeType;
+	}
+
+TTimeIntervalMicroSeconds CMidiClientUtility::CBody::PositionMicroSecondsL() const
+	{
+	TTimeIntervalMicroSeconds position;
+	User::LeaveIfError(iController.GetPosition(position));
+	return position;
+	}
+
+void CMidiClientUtility::CBody::SetPositionMicroSecondsL(const TTimeIntervalMicroSeconds& aPosition)
+	{
+	TTimeIntervalMicroSeconds maxPosition = DurationMicroSecondsL();
+	TTimeIntervalMicroSeconds minPosition(0);
+
+	TTimeIntervalMicroSeconds position = aPosition;
+	if (aPosition > maxPosition)
+		{
+		position = maxPosition;
+		}
+	if (aPosition < minPosition)
+		{
+		position = minPosition;
+		}
+	User::LeaveIfError(iController.SetPosition(position));
+	}
+
+TInt64 CMidiClientUtility::CBody::PositionMicroBeatsL() const
+	{
+	TInt64 position;
+	User::LeaveIfError(iMidiControllerCommands.PositionMicroBeats(position));
+	return position;
+	}
+
+void CMidiClientUtility::CBody::SetPositionMicroBeatsL(TInt64 aMicroBeats)
+	{
+	TInt64 maxPosition = DurationMicroBeatsL();
+	TInt64 minPosition(0);
+
+	TInt64 position = aMicroBeats;
+	if (aMicroBeats > maxPosition)
+		{
+		position = maxPosition;
+		}
+	if (aMicroBeats < minPosition)
+		{
+		position = minPosition;
+		}
+	User::LeaveIfError(iMidiControllerCommands.SetPositionMicroBeats(position));
+	}
+
+void CMidiClientUtility::CBody::SetSyncUpdateCallbackIntervalL(const TTimeIntervalMicroSeconds& aMicroSeconds, TInt64 aMicroBeats)
+	{
+	
+	if((aMicroSeconds > TTimeIntervalMicroSeconds(0)) || (aMicroSeconds == TTimeIntervalMicroSeconds(0) && aMicroBeats == 0))
+		{
+		iIntervalSec = ETrue;
+		}
+	else 
+		{
+		if (aMicroBeats > 0)
+			{
+			iIntervalSec = EFalse;
+			}
+		else
+			{
+			User::Leave(KErrArgument);
+			}
+		}
+	
+	User::LeaveIfError(iMidiControllerCommands.SetSyncUpdateCallbackInterval(aMicroSeconds, aMicroBeats));
+	}
+
+TInt CMidiClientUtility::CBody::SendMessageL(const TDesC8& aMidiMessage)
+	{
+	TInt numByteProc;
+	User::LeaveIfError(iMidiControllerCommands.SendMessage(aMidiMessage, numByteProc));
+	return numByteProc;
+	}
+
+TInt CMidiClientUtility::CBody::SendMessageL(const TDesC8& aMidiMessage,const TTimeIntervalMicroSeconds& aTime)
+	{
+	TInt numByteProc;
+	User::LeaveIfError(iMidiControllerCommands.SendMessage(aMidiMessage, aTime, numByteProc));
+	return numByteProc;
+	}
+
+void CMidiClientUtility::CBody::SendMipMessageL(const RArray<TMipMessageEntry>& aEntry)
+	{
+	User::LeaveIfError(iMidiControllerCommands.SendMipMessage(aEntry));
+	}
+
+TInt CMidiClientUtility::CBody::NumberOfBanksL(TBool aCustom) const
+	{
+	TInt numBanks;
+	User::LeaveIfError(iMidiControllerCommands.NumberOfBanks(aCustom, numBanks));
+	return numBanks;
+	}
+
+TInt CMidiClientUtility::CBody::GetBankIdL(TBool aCustom,TInt aBankIndex) const
+	{
+	TInt numBanks = NumberOfBanksL(aCustom);
+	TInt bankId = 0;
+	if(aBankIndex >= 0 && aBankIndex < numBanks)
+		{
+		User::LeaveIfError(iMidiControllerCommands.GetBankId(aCustom, aBankIndex, bankId));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	return bankId;
+	}
+
+void CMidiClientUtility::CBody::LoadCustomBankL(const TDesC& aFileName,TInt& aBankCollectionIndex)
+	{
+	User::LeaveIfError(iMidiControllerCommands.LoadCustomBank(aFileName, aBankCollectionIndex));
+	}
+
+void CMidiClientUtility::CBody::UnloadCustomBankL(TInt aBankCollectionIndex)
+	{
+	User::LeaveIfError(iMidiControllerCommands.UnloadCustomBank(aBankCollectionIndex));
+	}
+
+TBool CMidiClientUtility::CBody::CustomBankLoadedL(TInt aBankCollectionIndex) const
+	{
+	TBool bankLoaded;
+	User::LeaveIfError(iMidiControllerCommands.CustomBankLoaded(aBankCollectionIndex, bankLoaded));
+	return bankLoaded;
+	}
+
+void CMidiClientUtility::CBody::UnloadAllCustomBanksL()
+	{
+	User::LeaveIfError(iMidiControllerCommands.UnloadAllCustomBanks());
+	}
+
+TInt CMidiClientUtility::CBody::NumberOfInstrumentsL(TInt aBankId,TBool aCustom) const
+	{
+	TInt numInstruments;
+	User::LeaveIfError(iMidiControllerCommands.NumberOfInstruments(aBankId, aCustom, numInstruments));
+	return numInstruments;
+	}
+
+TInt CMidiClientUtility::CBody::GetInstrumentIdL(TInt aBankId,TBool aCustom,TInt aInstrumentIndex) const
+	{
+	TInt numInstruments = NumberOfInstrumentsL(aBankId, aCustom);
+	TInt instrumentId = 0;
+	if(aInstrumentIndex >=0 && aInstrumentIndex < numInstruments)
+		{
+		User::LeaveIfError(iMidiControllerCommands.GetInstrumentId(aBankId, aCustom, aInstrumentIndex, instrumentId));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	return instrumentId;
+	}
+
+HBufC* CMidiClientUtility::CBody::InstrumentNameL(TInt aBankId, TBool aCustom, TInt aInstrumentId) const
+	{
+	HBufC* instrumentName = NULL;
+
+	if(aInstrumentId >= KMinInstrumentId && aInstrumentId <= KMaxInstrumentId)
+		{
+		instrumentName = iMidiControllerCommands.InstrumentNameL(aBankId, aCustom, aInstrumentId);
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+
+	return instrumentName;
+	}
+
+void CMidiClientUtility::CBody::SetInstrumentL(TInt aChannel,TInt aBankId,TInt aInstrumentId)
+	{
+	if((aChannel >= KMinChannel && aChannel <= KMaxChannel)  
+	&& (aInstrumentId >= KMinInstrumentId && aInstrumentId <= KMaxInstrumentId))
+		{
+		User::LeaveIfError(iMidiControllerCommands.SetInstrument(aChannel, aBankId, aInstrumentId));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+void CMidiClientUtility::CBody::LoadCustomInstrumentL(const TDesC& aFileName, TInt aFileBankId, TInt aFileInstrumentId, TInt aMemoryBankId, TInt aMemoryInstrumentId)
+	{
+	if((aFileInstrumentId >= KMinInstrumentId && aFileInstrumentId <= KMaxInstrumentId) 
+	&& (aMemoryInstrumentId >= KMinInstrumentId && aMemoryInstrumentId <= KMaxInstrumentId))
+		{
+		User::LeaveIfError(iMidiControllerCommands.LoadCustomInstrument(aFileName, aFileBankId, aFileInstrumentId, aMemoryBankId, aMemoryInstrumentId));
+		}	
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+void CMidiClientUtility::CBody::UnloadCustomInstrumentL(TInt aCustomBankId,TInt aInstrumentId)
+	{
+	if(aInstrumentId >= KMinInstrumentId && aInstrumentId <= KMaxInstrumentId)
+		{
+		User::LeaveIfError(iMidiControllerCommands.UnloadCustomInstrument(aCustomBankId, aInstrumentId));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+HBufC* CMidiClientUtility::CBody::PercussionKeyNameL(TInt aNote, TInt aBankId, TBool aCustom, TInt aInstrumentId) const
+	{
+	HBufC* pKeyName = NULL;
+
+	if((aNote >= KMinNote && aNote <= KMaxNote) 
+	&& (aInstrumentId >= KMinInstrumentId && aInstrumentId <= KMaxInstrumentId))
+		{
+		pKeyName = iMidiControllerCommands.PercussionKeyNameL(aNote, aBankId, aCustom, aInstrumentId);
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+
+	return pKeyName;
+	}
+
+void CMidiClientUtility::CBody::StopTimeL(TTimeIntervalMicroSeconds& aStopTime) const
+	{
+	User::LeaveIfError(iMidiControllerCommands.StopTime(aStopTime));
+	}
+
+void CMidiClientUtility::CBody::SetStopTimeL(const TTimeIntervalMicroSeconds& aStopTime)
+	{
+	TTimeIntervalMicroSeconds duration = DurationMicroSecondsL();
+	if(aStopTime >= TTimeIntervalMicroSeconds(0) && aStopTime <= duration)
+		{
+		User::LeaveIfError(iMidiControllerCommands.SetStopTime(aStopTime));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+void CMidiClientUtility::CBody::SetRepeatsL(TInt aRepeatNumberOfTimes, const TTimeIntervalMicroSeconds& aTrailingSilence)
+	{
+	if((aRepeatNumberOfTimes >= 0) && (aTrailingSilence >= TTimeIntervalMicroSeconds(0)))
+		{
+		User::LeaveIfError(iMidiControllerCommands.SetRepeats(aRepeatNumberOfTimes, aTrailingSilence));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}	
+	}
+
+TInt CMidiClientUtility::CBody::PolyphonyL() const
+	{
+	TInt numNotes;
+	TInt maxPoly = MaxPolyphonyL();
+	User::LeaveIfError(iMidiControllerCommands.Polyphony(numNotes));
+	if(maxPoly <= numNotes)
+		{
+		return maxPoly;
+		}
+	else
+		{
+		return numNotes;	
+		}
+	}
+
+TInt CMidiClientUtility::CBody::MaxPolyphonyL() const
+	{
+	TInt maxNotes;
+	User::LeaveIfError(iMidiControllerCommands.MaxPolyphony(maxNotes));
+	return maxNotes;
+	}
+
+TInt CMidiClientUtility::CBody::ChannelsSupportedL() const
+	{
+	TInt channels;
+	User::LeaveIfError(iMidiControllerCommands.ChannelsSupported(channels));
+	return channels;
+	}
+
+TReal32 CMidiClientUtility::CBody::ChannelVolumeL(TInt aChannel) const
+	{
+	TReal32 channelVol;
+	if(aChannel >= KMinChannel && aChannel <= KMaxChannel) 
+		{
+		User::LeaveIfError(iMidiControllerCommands.ChannelVolume(aChannel, channelVol));
+		}
+	else
+		{
+		User::Leave(KErrArgument);	
+		}
+	return channelVol;
+	}
+
+TReal32 CMidiClientUtility::CBody::MaxChannelVolumeL() const
+	{
+	TReal32 maxChanVol;
+	User::LeaveIfError(iMidiControllerCommands.MaxChannelVolume(maxChanVol));
+	return maxChanVol;
+	}
+
+void CMidiClientUtility::CBody::SetChannelVolumeL(TInt aChannel,TReal32 aVolume)
+	{
+	TReal32 maxChanVol = MaxChannelVolumeL();
+	if((aChannel >= KMinChannel && aChannel <= KMaxChannel) && aVolume <= maxChanVol)
+		{
+		User::LeaveIfError(iMidiControllerCommands.SetChannelVolume(aChannel, aVolume));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+void CMidiClientUtility::CBody::SetChannelMuteL(TInt aChannel,TBool aMuted)
+	{
+	if(aChannel >= KMinChannel && aChannel <= KMaxChannel)
+		{
+		User::LeaveIfError(iMidiControllerCommands.SetChannelMute(aChannel, aMuted));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+TInt CMidiClientUtility::CBody::VolumeL() const
+	{
+	TInt vol;
+	User::LeaveIfError(iMidiControllerCommands.Volume(vol));
+	return vol;
+	}
+
+TInt CMidiClientUtility::CBody::MaxVolumeL() const
+	{
+	TInt maxVol;
+	User::LeaveIfError(iMidiControllerCommands.MaxVolume(maxVol));
+	return maxVol;
+	}
+
+void CMidiClientUtility::CBody::SetVolumeL(TInt aVolume)
+	{
+	User::LeaveIfError(iMidiControllerCommands.SetVolume(aVolume));
+	}
+
+void CMidiClientUtility::CBody::SetVolumeRampL(const TTimeIntervalMicroSeconds& aRampDuration)
+	{
+	User::LeaveIfError(iMidiControllerCommands.SetVolumeRamp(aRampDuration));
+	}
+
+
+TInt CMidiClientUtility::CBody::GetBalanceL() const
+	{
+	TInt balance;
+	User::LeaveIfError(iMidiControllerCommands.GetBalance(balance));
+	return balance;
+	}
+
+void CMidiClientUtility::CBody::SetBalanceL(TInt aBalance)
+	{
+	User::LeaveIfError(iMidiControllerCommands.SetBalance(aBalance));
+	}
+
+void CMidiClientUtility::CBody::SetPriorityL(TInt aPriority, TInt aPref)
+	{
+	TMMFPrioritySettings priority;
+	priority.iPriority = aPriority;
+	priority.iPref = aPref;
+
+	User::LeaveIfError(iController.SetPrioritySettings(priority));
+	}
+
+TInt CMidiClientUtility::CBody::NumberOfMetaDataEntriesL() const
+	{
+	TInt numMetaData;
+	User::LeaveIfError(iController.GetNumberOfMetaDataEntries(numMetaData));
+	return numMetaData;
+	}
+
+CMMFMetaDataEntry* CMidiClientUtility::CBody::GetMetaDataEntryL(TInt aMetaDataIndex) const
+	{
+	CMMFMetaDataEntry* metaDataEntry = iController.GetMetaDataEntryL(aMetaDataIndex);
+	return metaDataEntry;
+	}
+
+void CMidiClientUtility::CBody::CustomCommandSyncL(const TMMFMessageDestinationPckg& aDestination, TInt aFunction, const TDesC8& aDataTo1, const TDesC8& aDataTo2, TDes8& aDataFrom)
+	{
+	User::LeaveIfError(iController.CustomCommandSync(aDestination, aFunction, aDataTo1, aDataTo2, aDataFrom));
+	}
+
+void CMidiClientUtility::CBody::CustomCommandSyncL(const TMMFMessageDestinationPckg& aDestination, TInt aFunction, const TDesC8& aDataTo1, const TDesC8& aDataTo2)
+	{
+	User::LeaveIfError(iController.CustomCommandSync(aDestination, aFunction, aDataTo1, aDataTo2));
+	}
+
+void CMidiClientUtility::CBody::CustomCommandAsync(const TMMFMessageDestinationPckg& aDestination, TInt aFunction, const TDesC8& aDataTo1, const TDesC8& aDataTo2, TDes8& aDataFrom, TRequestStatus& aStatus)
+	{
+	iController.CustomCommandAsync(aDestination, aFunction, aDataTo1, aDataTo2, aDataFrom, aStatus);
+	}
+
+void CMidiClientUtility::CBody::CustomCommandAsync(const TMMFMessageDestinationPckg& aDestination, TInt aFunction, const TDesC8& aDataTo1, const TDesC8& aDataTo2, TRequestStatus& aStatus)
+	{
+	iController.CustomCommandAsync(aDestination, aFunction, aDataTo1, aDataTo2, aStatus);
+	}
+
+MMMFDRMCustomCommand* CMidiClientUtility::CBody::GetDRMCustomCommand()
+	{
+	if (iDRMCustomCommands.IsSupported())
+		{
+		return static_cast<MMMFDRMCustomCommand*>(&iDRMCustomCommands);
+		}
+	return NULL;
+	}
+	
+TInt CMidiClientUtility::CBody::DoOpen(const RMMFControllerImplInfoArray& aControllers, TUid aSinkUid, const TDesC8& aSinkData, TBool aUseSharedHeap)
+	{
+	// Make sure any existing controller is closed.
+	iMidiControllerEventMonitor->Cancel();
+	iController.Close();
+
+	// Try opening and configuring each controller in turn
+	TInt error = KErrNotSupported;
+	TInt index = 0;
+	while (error)
+		{
+		// Break if we're at the end of the array of controllers
+		if (index >= aControllers.Count())
+			break;
+
+		// Open the controller
+		error = iController.Open(aControllers[index]->Uid(), iPrioritySettings, aUseSharedHeap);
+
+		// If the controller was opened without error, start receiving events from it.
+		if (error==KErrNone)
+			{
+			iMidiControllerEventMonitor->Start();
+			}
+
+		// Add the data sink
+		if (error==KErrNone)
+			error = iController.AddDataSink(aSinkUid, aSinkData, iSinkHandle);
+
+		// If an error occurred in any of the above, close the controller.
+		if (error!=KErrNone)
+			{
+			iMidiControllerEventMonitor->Cancel();
+			iController.Close();
+			}
+
+		// increment index
+		index++;
+		}
+
+	return error;
+	}
+
+   void CMidiClientUtility::CBody::HandleMidiEvent(const CMMFMidiEvent& aEvent)
+   	{
+   	if(aEvent.iEventType == KMMFEventCategoryMidiOpenDataSourceComplete ||
+   	   aEvent.iEventType == KMMFEventCategoryMidiClose ||
+   	   aEvent.iEventType == KMMFEventCategoryMidiPrime ||
+   	   aEvent.iEventType == KMMFEventCategoryMidiPlaying ||
+   	   aEvent.iEventType == KMMFEventCategoryMidiPlaybackIncompatible ||
+   	   aEvent.iEventType == KMMFEventCategoryMidiPlaybackSilent)
+   		{
+   		iState = aEvent.iNewState;
+   		iObserver.MmcuoStateChanged(aEvent.iOldState, aEvent.iNewState, aEvent.iMicroSeconds, aEvent.iErrorCode);
+   		
+   		if (aEvent.iEventType == KMMFEventCategoryMidiClose)
+   			{
+			if (iSourceHandle.DestinationHandle())
+				{
+				iController.RemoveDataSource(iSourceHandle);
+				}
+			}	
+ 		}
+   	else if(aEvent.iEventType == KMMFEventCategoryMidiPlayingComplete)
+   		{
+ 		iState = aEvent.iNewState;
+   		iObserver.MmcuoStateChanged(aEvent.iOldState, aEvent.iNewState, aEvent.iMicroSeconds, aEvent.iErrorCode);
+   		}
+   	else if(aEvent.iEventType == KMMFEventCategoryMidiSyncUpdate)
+   		{
+   		iObserver.MmcuoSyncUpdate(aEvent.iMicroSeconds, aEvent.iMicroBeats);
+   		}
+   	else if(aEvent.iEventType == KMMFEventCategoryTempoChanged)
+   		{
+   		iObserver.MmcuoTempoChanged(aEvent.iTempoMicroBeats);
+   		}
+   	else if(aEvent.iEventType == KMMFEventCategoryVolumeChanged)
+   		{
+   		iObserver.MmcuoVolumeChanged(aEvent.iChannel, aEvent.iVolumeInDecibels);
+   		}
+   	else if(aEvent.iEventType == KMMFEventCategoryMuteChanged)
+   		{
+   		iObserver.MmcuoMuteChanged(aEvent.iChannel, aEvent.iMute);
+   		}
+   	else if(aEvent.iEventType == KMMFEventCategoryMetaDataEntryFound)
+   		{
+   		iObserver.MmcuoMetaDataEntryFound(aEvent.iMetaDataEntryId, aEvent.iMicroSeconds);
+   		}
+   	else if(aEvent.iEventType == KMMFEventCategoryMipMessageReceived)
+   		{
+   		iObserver.MmcuoMipMessageReceived(aEvent.iMipMessage);
+   		}
+   	else if(aEvent.iEventType == KMMFEventCategoryPolyphonyChanged)
+   		{
+   		iObserver.MmcuoPolyphonyChanged(aEvent.iPolyphony);
+   		}
+   	else if(aEvent.iEventType == KMMFEventCategoryInstrumentChanged)
+   		{
+   		iObserver.MmcuoInstrumentChanged(aEvent.iChannel,aEvent.iBankId,aEvent.iInstrumentId);
+   		}
+   	else if((iState == EMidiStateOpenPlaying) || (iState == EMidiStatePlaybackIncompatible) || 
+   			(iState == EMidiStatePlaybackSilent) || (iState == EMidiStateClosedEngaged) ||
+   			(iState == EMidiStateOpenEngaged))
+   		{
+ 		iState = aEvent.iNewState;
+   		iObserver.MmcuoStateChanged(aEvent.iOldState, aEvent.iNewState, aEvent.iMicroSeconds, aEvent.iErrorCode);
+
+   		}
+   	else if (aEvent.iEventType == KMMFErrorCategoryControllerGeneralError)
+   		{
+   		iObserver.MmcuoStateChanged(iState, iState, TTimeIntervalMicroSeconds(0), aEvent.iErrorCode);
+   		}
+   	else
+   		{
+   		// FIXME - what do we do when we don't understand the error type?
+   		}
+   	}
+
+/**
+ *
+ * Used to change the value of MaxPolyphonyL()
+ */ 	
+void CMidiClientUtility::CBody::SetMaxPolyphonyL(TInt aMaxNotes)
+	{
+	User::LeaveIfError(iMidiControllerCommands.SetMaxPolyphony(aMaxNotes));
+	}
+
+TInt CMidiClientUtility::CBody::GetRepeats()
+	{
+	TInt numRepeats = 0;
+	iMidiControllerCommands.GetRepeats(numRepeats);
+	return numRepeats;
+	}
+
+void CMidiClientUtility::CBody::LoadCustomBankDataL(const TDesC8& aBankData,TInt& aBankId)
+	{
+	User::LeaveIfError(iMidiControllerCommands.LoadCustomBankData(aBankData, aBankId));
+	}
+
+void CMidiClientUtility::CBody::LoadCustomInstrumentDataL(const TDesC8& aInstrumentData, TInt aBankDataId, TInt aInstrumentDataId, TInt aMemoryBankId, TInt aMemoryInstrumentId)
+	{
+	if((aInstrumentDataId >= KMinInstrumentId && aInstrumentDataId <= KMaxInstrumentId) 
+	&& (aMemoryInstrumentId >= KMinInstrumentId && aMemoryInstrumentId <= KMaxInstrumentId))
+		{
+		User::LeaveIfError(iMidiControllerCommands.LoadCustomInstrumentData(aInstrumentData, aBankDataId, aInstrumentDataId, aMemoryBankId, aMemoryInstrumentId));
+		}
+	else
+		{
+		User::Leave(KErrArgument);
+		}
+	}
+
+void CMidiClientUtility::CBody::SetBankL(TBool aCustom)
+	{
+	User::LeaveIfError(iMidiControllerCommands.SetBank(aCustom));
+	}
+
+TBool CMidiClientUtility::CBody::IsTrackMuteL(TInt aTrack) const
+	{
+	TBool mute;
+	User::LeaveIfError(iMidiControllerCommands.IsTrackMute(aTrack, mute));
+	return mute;
+	}
+
+TBool CMidiClientUtility::CBody::IsChannelMuteL(TInt aChannel) const
+	{
+	TBool mute;
+	if (aChannel >= KMinChannel && aChannel <= KMaxChannel)
+		{
+		User::LeaveIfError(iMidiControllerCommands.IsChannelMute(aChannel, mute));	
+		}
+	else
+		{
+		User::Leave(KErrArgument);	
+		}
+		
+	return mute;
+	}
+
+void CMidiClientUtility::CBody::GetInstrumentL(TInt aChannel, TInt& aInstrumentId, TInt& aBankId)
+	{
+	if (aChannel >= KMinChannel && aChannel <= KMaxChannel)
+		{
+		User::LeaveIfError(iMidiControllerCommands.GetInstrument(aChannel, aInstrumentId, aBankId));	
+		}
+	else
+		{
+		User::Leave(KErrArgument);		
+		}
+	}
+
+void CMidiClientUtility::CBody::RepeatTrailingSilenceTimerComplete()
+	{
+	Play();
+	}
+
+CRepeatTrailingSilenceTimer* CRepeatTrailingSilenceTimer::NewL(MRepeatTrailingSilenceTimerObs& aObs)
+	{
+	CRepeatTrailingSilenceTimer* s = new(ELeave) CRepeatTrailingSilenceTimer(aObs);
+	CleanupStack::PushL(s);
+	s->ConstructL();
+	CleanupStack::Pop();
+	return s;
+	}
+
+void CRepeatTrailingSilenceTimer::RunL()
+	{
+	iObs.RepeatTrailingSilenceTimerComplete();
+	}
+
+CRepeatTrailingSilenceTimer::CRepeatTrailingSilenceTimer(MRepeatTrailingSilenceTimerObs& aObs) :
+	CTimer(EPriorityHigh),
+	iObs(aObs)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+//
+//
+//
+//
+
+CMidiControllerEventMonitor* CMidiControllerEventMonitor::NewL(MMidiControllerEventMonitorObserver& aMidiObserver, 
+												RMidiControllerCustomCommands& aMidiControllerCustomCommands, const CMidiClientUtility& aParent)
+	{
+	CMidiControllerEventMonitor* self = new(ELeave) CMidiControllerEventMonitor(aMidiObserver, aMidiControllerCustomCommands, aParent);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+void CMidiControllerEventMonitor::ConstructL()
+	{
+	iMidiEvent = new (ELeave) CMMFMidiEvent();
+	}
+
+CMidiControllerEventMonitor::CMidiControllerEventMonitor(MMidiControllerEventMonitorObserver& aMidiObserver, 
+													   RMidiControllerCustomCommands& aMidiControllerCustomCommands, const CMidiClientUtility& aParent) :
+	CActive(EPriorityStandard),
+	iMidiObserver(aMidiObserver), 
+	iMidiControllerCustomCommands(aMidiControllerCustomCommands),
+	iParent(aParent)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CMidiControllerEventMonitor::~CMidiControllerEventMonitor()
+	{
+	Cancel();
+	delete iMidiEvent;
+	}
+
+/**
+Start receiving events from the controller.
+
+This can only be called once the controller is open.
+*/
+void CMidiControllerEventMonitor::Start()
+	{
+	iMidiControllerCustomCommands.ReceiveEvents(iSizeOfEvent, iStatus);
+	SetActive();
+	}
+
+void CMidiControllerEventMonitor::RunL()
+	{
+	User::LeaveIfError(iStatus.Int());
+
+	// Create a buffer big enough to hold the event, then retrieve it from the server
+	HBufC8* buf = HBufC8::NewLC(iSizeOfEvent());
+	TPtr8 bufPtr = buf->Des();
+	User::LeaveIfError(iMidiControllerCustomCommands.RetrieveEvent(bufPtr));
+
+	// Now internalize a CMMFMidiEvent with the info in the buffer
+	RDesReadStream stream(bufPtr);
+	CleanupClosePushL(stream);
+
+	CMMFMidiEvent* theEvent = new (ELeave) CMMFMidiEvent();
+	
+	CleanupStack::PushL(theEvent);
+	theEvent->InternalizeL(stream);
+	
+	iMidiObserver.HandleMidiEvent(*theEvent);
+	Start();
+
+	CleanupStack::PopAndDestroy(3);//buf, stream, theEvent
+	}
+
+void CMidiControllerEventMonitor::SelfComplete(TInt aError)
+	{
+	Cancel();
+	TRequestStatus *status = &iStatus;
+	if(!IsActive())
+		SetActive();
+	User::RequestComplete(status, aError);
+	}
+
+void CMidiControllerEventMonitor::DoCancel()
+	{
+	iMidiControllerCustomCommands.CancelReceiveEvents();
+	}
+
+TInt CMidiControllerEventMonitor::RunError(TInt aError)
+	{
+	iMidiEvent->iEventType = KMMFErrorCategoryControllerGeneralError;
+	iMidiEvent->iErrorCode = aError;
+	iMidiEvent->iOldState = iParent.State();
+	iMidiEvent->iNewState = iMidiEvent->iOldState;
+
+	iMidiObserver.HandleMidiEvent(*iMidiEvent);
+	Start();
+	return KErrNone;
+	}