srsf/sisrscontrollerplugin/src/sindetraining.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:29:17 +0100
branchRCL_3
changeset 19 e36f3802f733
parent 0 bf1d17376201
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2006 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:  Implementation for CSindeTrainer
*
*/


// INCLUDE FILES
#include <e32base.h>
#include <badesca.h>
#include <numberconversion.h>
#include "sindetraining.h"
#include "rubydebug.h"
#include "sidatabase.h"
#include "sigrammardb.h"
#include "silexicondb.h"

// CONSTANTS

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CSindeTrainer::CSindeTrainer
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CSindeTrainer::CSindeTrainer( CDevASR& aDevAsr,
                              CSIControllerPluginInterface& aControllerIf,
                              CSIControllerPlugin& aPlugin,
                              CSIDatabase& aDatabase,
                              CSIGrammarDB& aGrammarDatabase,
                              CSILexiconDB& aLexiconDatabase ) :
                              CActive( EPriorityStandard ), 
                              iState( ESindeTrainerIdle ),
                              iDevAsr( aDevAsr ),
                              iControllerIf( aControllerIf ),
                              iPlugin( aPlugin ),
						      iDatabase( aDatabase ),
                              iGrammarDatabase( aGrammarDatabase ),
                              iLexiconDatabase( aLexiconDatabase )
    {
    // Nothing
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSindeTrainer::ConstructL()
    {
    RUBY_DEBUG_BLOCK( "CSindeTrainer::ConstructL" );
    
    // Add active object to active scheduler
    CActiveScheduler::Add( this );
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSindeTrainer* CSindeTrainer::NewL( CDevASR& aDevAsr,
                                    CSIControllerPluginInterface& aControllerIf,
                                    CSIControllerPlugin& aPlugin,
                                    CSIDatabase& aDatabase,
                                    CSIGrammarDB& aGrammarDatabase,
                                    CSILexiconDB& aLexiconDatabase )
    {
    RUBY_DEBUG_BLOCK( "CSindeTrainer::NewL" );
    CSindeTrainer* self = new( ELeave ) CSindeTrainer( aDevAsr, aControllerIf, aPlugin,
     										           aDatabase, aGrammarDatabase,
     										           aLexiconDatabase );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );	
    return self;
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::~CSindeTrainer
// Destructor
// -----------------------------------------------------------------------------
//
CSindeTrainer::~CSindeTrainer()
    {
    RUBY_DEBUG0( "CSindeTrainer::~CSindeTrainer" );
    
    Cancel();

    delete iTtpWordList;
    iMaxPronunsForWord.Close();
    
    iTtpDataArray.ResetAndDestroy();
    iTtpDataArray.Close();
    
    if ( iTrainArrays != NULL )
        {
        iTrainArrays->ResetAndDestroy();
        iTrainArrays->Close();
        delete iTrainArrays;
        }
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::SetReady
// Sets the object active and signals active scheduler to run it.
// -----------------------------------------------------------------------------
//
void CSindeTrainer::SetReady()
    {
    TRequestStatus* pRS = &iStatus;
    User::RequestComplete( pRS, KErrNone );
    SetActive();
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::RunL
// RunL of CActive
// -----------------------------------------------------------------------------
//
void CSindeTrainer::RunL()
    {
    RUBY_DEBUG0( "CSindeTrainer::RunL" );
    
    switch ( iState )
        {
        case ESindeTrainerTraining:
            {
            TRAPD( error, DoOneTrainingStepL() );
            if ( error != KErrNone )
                {
                // Move to next state
                iState = ESindeTrainerDbUpdate;
                SetReady();
                }
            break;
            }
        
        case ESindeTrainerDbUpdate:
            {
            TRAPD( error, DoDatabaseUpdateL() );
            iError = error;
            iState = ESindeGrammarCompilation;
            SetReady();
            break;
            }
        
        case ESindeGrammarCompilation:
            {
            TRAPD( error, DoGrammarCompilationL() );
            iError = error;
            if ( error != KErrNone )
                {
                // Move to next state
                iState = ESindeTrainerFinished;
                SetReady();                
                }
            break;
            }
        
        case ESindeTrainerFinished:
            {
            RUBY_DEBUG1( "CSindeTrainer::RunL sending KUidAsrEventAddVoiceTags callback with error: %d", iError );
            // All done, do callback to client thread     
            iControllerIf.SendSrsEvent( KUidAsrEventAddVoiceTags, iError );
            iState = ESindeTrainerIdle;            
            break;   
            }
        
        default:
            RUBY_ERROR0( "CSindeTrainer::RunL unexpected state" );
            break;
       
        }
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::DoCancel
// DoCancel of CActive
// -----------------------------------------------------------------------------
//
void CSindeTrainer::DoCancel()
    {
    RUBY_DEBUG0( "CSindeTrainer::DoCancel" );
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::HandleEvent
// Handles event originated from DevASR
// -----------------------------------------------------------------------------
//
void CSindeTrainer::HandleEvent( TDevASREvent aEvent, TDevASRError aError )
    {
    RUBY_DEBUG2( "CSindeTrainer::HandleEvent event: %d error: %d", aEvent, aError );
    
    if ( aError == KErrNone )
        {
        if ( aEvent == EDevASRTrainFromText )
            {
            // Store the data
            iTtpDataArray.Append( iTtpWordList );
            // Ownership transferred to array
            iTtpWordList = NULL;
            }
        else if ( aEvent == EDevASRGrammarCompile )
            {
            StoreCompiledGrammar();
            iState = ESindeTrainerFinished;
            }
        }
    
    // Do the next step in RunL
    SetReady();
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::AddSindeVoiceTagsL
// Starts training of SINDE voice tags
// -----------------------------------------------------------------------------
//
void CSindeTrainer::AddSindeVoiceTagsL( RPointerArray<MDesCArray>* aTrainArrays,
	                                    RArray<RLanguageArray>& aLanguageArray, 
                                        TSILexiconID aLexiconId,
                                        TSIGrammarID aGrammarId,
                                        TSIModelBankID aModelBankId,
                                        TUid aClientUid,
                                        RArray<TSIRuleID>& aRuleIds )
    {
    RUBY_DEBUG_BLOCK( "CSindeTrainer::AddSindeVoiceTagsL" );
    
    if ( IsActive() )
        {
        User::Leave( KErrInUse );
        }
        
    // Start reading the input arrays from zero index
    iLanguageIndex = 1;
    iTextIndex = 0;
    
    // Destruct previous input if it still exists
    if ( iTrainArrays != NULL )
        {
        iTrainArrays->ResetAndDestroy();
        iTrainArrays->Close();
        delete iTrainArrays;
        iTrainArrays = NULL;
        }
    
    // Store parameters for asynchronous processing
    iTrainArrays = aTrainArrays;
    iLanguageArray = &aLanguageArray;
    iLexiconId = aLexiconId;
    iGrammarId = aGrammarId;
    iClientUid = aClientUid;
    iModelBankId = aModelBankId;
    iRuleIds = &aRuleIds;
    
    iState = ESindeTrainerTraining;
    SetReady();
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::DoOneTrainingStep
// Starts one step of training using DevASR
// -----------------------------------------------------------------------------
//
void CSindeTrainer::DoOneTrainingStepL()
    {
    RUBY_DEBUG_BLOCK( "CSindeTrainer::DoOneTrainingStepL" );
    
    // Delete the previous DevASR input data
    delete iTtpWordList;
    iTtpWordList = NULL;
    iTtpWordList = CSITtpWordList::NewL();
    
    for ( TInt i = 0; i < iTrainArrays->Count(); i++ )
        {
        MDesCArray* originalText = (*iTrainArrays)[i];
            
        CDesC16ArrayFlat* wordArray = new ( ELeave ) CDesC16ArrayFlat( 1 );
        CleanupStack::PushL( wordArray );
            
        // Loop through all descriptors that are needed for this group and
        // add them to new wordArray
        for ( TInt j = 0; j < originalText->MdcaCount(); j++ )
            {
            TInt textLength = originalText->MdcaPoint( j ).Length();
            if ( textLength > 0 )
                {
                TPtrC firstChar( originalText->MdcaPoint( j ).Left( 1 ) );
                TInt length( 0 );
                TInt result( 0 );
                TDigitType type;
                result = NumberConversion::ConvertFirstNumber( firstChar, length, type );
                
                if ( result == iLanguageIndex )
                    {
                    // Take off the first character
                    TPtrC text( originalText->MdcaPoint( j ).Right( textLength - 1 ) );
                    wordArray->AppendL( text ); 
                    }
                }
            }
            
            // Append empty descriptor if nothing else was found
            if ( wordArray->Count() == 0 )
                {
                wordArray->AppendL( KNullDesC ); 
                }
                
        iTtpWordList->AddL( wordArray );
        // Ownership transferred to iTtpWordList
        CleanupStack::Pop( wordArray );
        }
        
    // Decrease 1 to get the current index, iLanguageIndex starts from 1
    TInt currentLanguageIndex( iLanguageIndex - 1 );
        
     // Check that there is legal index for languageArray available
    if ( ( currentLanguageIndex < 0 ) || ( currentLanguageIndex >= iLanguageArray->Count() ) )
        {
        RUBY_ERROR0( "CSindeTrainer::DoOneTrainingStep language array index out of bounds" );
        User::Leave( KErrNotFound );
        }
        
    iMaxPronunsForWord.Reset();	
    iMaxPronunsForWord.Append( (*iLanguageArray)[currentLanguageIndex].Count() );
        
    // Do the training call to DevASR
    iDevAsr.StartTrainingFromTextL( *iTtpWordList, (*iLanguageArray)[currentLanguageIndex], iMaxPronunsForWord );

    // Move to next group          
    iLanguageIndex++;
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::DoDatabaseUpdateL
// Stores the training results into grammar and lexicon and updates the DB
// -----------------------------------------------------------------------------
//
void CSindeTrainer::DoDatabaseUpdateL()
    {
    RUBY_DEBUG_BLOCK( "CSindeTrainer::DoDatabaseUpdateL" );
   
    iRuleIds->Reset();
   
    iDatabase.BeginTransactionL();
    
    // Get the grammar
    iGrammarDatabase.VerifyOwnershipL( iClientUid, KGrammarIdTable, KGrammarIndex, iGrammarId ); 
    CSICompiledGrammar* grammar = ( CSICompiledGrammar* ) iGrammarDatabase.GrammarL( iGrammarId );
    CleanupStack::PushL( grammar );	
    
    // Get the lexicon
    iLexiconDatabase.VerifyOwnershipL( iClientUid, KLexiconIdTable, KLexiconIndex, iLexiconId );		   
    CSILexicon* lexicon = iLexiconDatabase.LexiconL( iLexiconId );
    CleanupStack::PushL( lexicon );	
    
    iDatabase.CommitChangesL( EFalse ); 
    
    // There should be at least one element in ttp data array
    if ( iTtpDataArray.Count() > 0 )
    	{
    	// Take the first word list
        CSITtpWordList* ttpWordList = iTtpDataArray[0];
        
        for ( TInt i = 0; i < ttpWordList->Count(); i++ )
            {
            RPointerArray<CSIPronunciationInfo> pronunciations;
            RArray<TSIPronunciationID> pronunciationIDs;
            CleanupClosePushL( pronunciationIDs );
            CleanupClosePushL( pronunciations );
            // Take the pronunciations from ttp output
            ttpWordList->GetPronunciationsL( i, pronunciations );

            CSIRule* rule = iPlugin.CreateNewRuleL( grammar );
            CleanupStack::PushL( rule );	
            
            // if pronunciation generation failed, skip that word.
            if ( pronunciations.Count() == 0 )
                {
                User::LeaveIfError( iRuleIds->Append( KInvalidRuleID ) );
                CleanupStack::PopAndDestroy( rule );
                }
            else
                {
            	for ( TInt k = 0; k < pronunciations.Count(); k++ ) 
                	{
               		pronunciationIDs.Reset();
            
                    for ( TInt n = 0; n < pronunciations[k]->Count(); n++ ) 
                        {
                    	// Add Pronunciation into lexicon
                        TDesC8& pronunciation = pronunciations[k]->PronunciationL( n );
                        TSIPronunciationID pronunId = iPlugin.CreateNewPronunciationL( lexicon, pronunciation, iModelBankId );
                        User::LeaveIfError( pronunciationIDs.Append( pronunId ) );
                	    }

                    AppendPronunciationsL( i, *lexicon, pronunciationIDs );
            
            	    // Add RuleVariant into grammar
            	    iPlugin.AddNewRuleVariantL( *rule, iLexiconId, pronunciationIDs, *pronunciations[k] );
            	    }
        
        	    grammar->AddL( rule );
        	    CleanupStack::Pop( rule );
            
                // Add rule to client side array      
                User::LeaveIfError( iRuleIds->Append( rule->RuleID() ) );
                }
                   
        	// Close the arrays
        	CleanupStack::PopAndDestroy( &pronunciations ); 
        	CleanupStack::PopAndDestroy( &pronunciationIDs );

            } // for ( TInt i = 0; i < ttpWordList->Count(); i++ )

        // Do the updates into the database
        iDatabase.BeginTransactionL();
        iGrammarDatabase.UpdateGrammarL( iClientUid, grammar );
        iLexiconDatabase.UpdateLexiconL( iClientUid, lexicon );
        // Commit changes to db with compact
        iDatabase.CommitChangesL( ETrue );  
        } // if ( iTtpDataArray.Count() > 0 )

    CleanupStack::PopAndDestroy( lexicon );
    CleanupStack::PopAndDestroy( grammar );	
        
    // All data has been stored elsewhere
    iTtpDataArray.ResetAndDestroy();
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::DoGrammarCompilationL
// Does grammar compilation using DevASR
// -----------------------------------------------------------------------------
//
void CSindeTrainer::DoGrammarCompilationL()
    {
    iDatabase.BeginTransactionL();
    iCompiledGrammar = ( CSICompiledGrammar* )iGrammarDatabase.LoadGrammarL( iGrammarId );
    iDatabase.CommitChangesL( EFalse );
            
    iDevAsr.CompileGrammarL( *iCompiledGrammar );
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::StoreCompiledGrammar
// Stores compiled grammar to plugin database
// -----------------------------------------------------------------------------
//
void CSindeTrainer::StoreCompiledGrammar()
    {
    TRAP_IGNORE( 
        iDatabase.BeginTransactionL();
        // save the compiled grammar
        iGrammarDatabase.UpdateGrammarL( iClientUid, iCompiledGrammar );
        iDatabase.CommitChangesL( ETrue );
        ); // TRAP_IGNORE
    }

// -----------------------------------------------------------------------------
// CSindeTrainer::AppendPronunciationsL
// Appends pronunciations from other ttp word lists than the first one
// -----------------------------------------------------------------------------
//
void CSindeTrainer::AppendPronunciationsL( TInt aIndex, CSILexicon& aLexicon, 
                                           RArray<TSIPronunciationID>& aPronunIds )
    {
    // Append pronunciations also from other word lists
    for ( TInt counter = 1; counter < iTtpDataArray.Count(); counter++ )
        {
        CSITtpWordList* ttpWordList = iTtpDataArray[counter];
        RPointerArray<CSIPronunciationInfo> pronunciations;
        CleanupClosePushL( pronunciations );
        // Take the same index as from first word list
        ttpWordList->GetPronunciationsL( aIndex, pronunciations );
                        
        for ( TInt pronunArrayCounter = 0; pronunArrayCounter < pronunciations.Count(); pronunArrayCounter++ )
            {
            for ( TInt pronunCounter = 0; pronunCounter < pronunciations[pronunArrayCounter]->Count(); pronunCounter++ )
                {
                TDesC8& pronun = pronunciations[pronunArrayCounter]->PronunciationL( pronunCounter );
                TSIPronunciationID pronunId = iPlugin.CreateNewPronunciationL( &aLexicon, pronun, iModelBankId );
                User::LeaveIfError( aPronunIds.Append( pronunId ) );
                }
            }
            CleanupStack::PopAndDestroy( &pronunciations ); 
        }
    }
    
// End of File