srsf/sisrscontrollerplugin/src/simodelbankdb.cpp
branchRCL_3
changeset 19 e36f3802f733
parent 0 bf1d17376201
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/srsf/sisrscontrollerplugin/src/simodelbankdb.cpp	Wed Sep 01 12:29:17 2010 +0100
@@ -0,0 +1,875 @@
+/*
+* Copyright (c) 2004-2008 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:  This class handles the storage and access of user trained models
+*               and utterances into a database.  It performs checksum verification
+*               for the stored data.  It is also responsible for allocating memory
+*               when loading the models into the recognizer.
+*
+*/
+
+
+// INCLUDE FILES
+#include <e32std.h>
+#include <e32base.h>
+#include <f32file.h>
+#include "siresourcehandler.h"
+#include "asrplugindataloader.h"
+#include "simodelbankdb.h"
+#include "rubydebug.h"
+
+// CONSTANTS
+const TInt KModelBankPackageType=3;
+const TInt KModelBankLanguageType=0;
+const TInt KModelBankStartPos=0;
+
+// _LIT(KModelFileName,"c:\\system\\Apps\\model_data\\qhmms_fxp"); // Commented out to remove "not referenced" warning
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::CSIModelBankDB
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CSIModelBankDB::CSIModelBankDB( RDbNamedDatabase& aDatabase, 
+                                RDbs& aDbSession,
+                                TInt aDrive )
+                               : CSICommonDB(aDatabase, aDbSession, aDrive ),
+                                 iAcousticModelPtr(0,0,0)
+    {
+    }
+
+ // -----------------------------------------------------------------------------
+// CSIModelBankDB::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::ConstructL()
+    {
+    RUBY_DEBUG_BLOCK( "CSIModelBankDB::ConstructL" );
+
+    // Resource handler 
+    CSIResourceHandler* resourceHandler = CSIResourceHandler::NewL();
+    CleanupStack::PushL(resourceHandler);
+    //  Data loader
+    iDataLoader = CDataLoader::NewL( 
+        *(resourceHandler->iDataFilenamePrefix), 
+        *(resourceHandler->iDataFilenameSeperator),
+        *(resourceHandler->iDataFilenamePostfix) );
+    CleanupStack::PopAndDestroy(1); //resourceHandler
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CSIModelBankDB* CSIModelBankDB::NewL( RDbNamedDatabase& aDatabase, 
+                                      RDbs& aDbSession,
+                                      TInt aDrive )
+    {
+    RUBY_DEBUG_BLOCK( "CSIModelBankDB::NewL" );
+    
+    CSIModelBankDB* self 
+        = new( ELeave ) CSIModelBankDB( aDatabase, aDbSession, aDrive );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();	
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::~CSIModelBankDB
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CSIModelBankDB::~CSIModelBankDB()
+{
+	// Delete all elements of the array before deleting the array
+	iModelBankArray.ResetAndDestroy();
+	iModelBankArray.Close();
+	
+ 	delete iDataLoader;
+}
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::GetAllAcousticModelsL
+// 
+// -----------------------------------------------------------------------------
+//
+const CSIModelBank* CSIModelBankDB::GetAllAcousticModelsL( TSIModelBankID aModelBankID ) 
+    {
+    
+    // Construct the table name using the provided model bank ID
+    TBuf<40> KModelBankName(KSIModelBankTable);
+    KModelBankName.AppendNumUC(aModelBankID);
+    
+    TBuf<100> KSQLStatement;
+    // Declare a literal string to hold the SQL statement
+    // SELECT  KHmmColumn, KHmmChecksumColumn FROM KModelBankName
+    _LIT(KSQLSelect1, "SELECT ");
+    _LIT(KSQLSelect2, " FROM ");
+    
+    KSQLStatement = KSQLSelect1;
+    KSQLStatement.Append(KHmmColumn);
+    KSQLStatement.Append(KNext);
+    KSQLStatement.Append(KHmmChecksumColumn);
+    KSQLStatement.Append(KSQLSelect2);
+    KSQLStatement.Append(KModelBankName);
+    
+    RDbView view;
+    CleanupClosePushL(view);
+    User::LeaveIfError(view.Prepare(iDb, TDbQuery(KSQLStatement, EDbCompareNormal)));
+    User::LeaveIfError(view.EvaluateAll());
+    
+    // Get column set for column ordinals
+    CDbColSet* columns = view.ColSetL();
+    TDbColNo hmm_col = columns->ColNo(KHmmColumn);
+    TDbColNo hmmchecksum_col = columns->ColNo(KHmmChecksumColumn);
+    delete columns;
+    
+    // Create a model bank object
+    CSIModelBank* modelBank = CSIModelBank::NewLC(aModelBankID);
+    
+    TSIModelID modelID=KModelID;
+    TInt length;
+    TInt32 checksum;
+    // After evaluation, the first call to NextL() is equivalent to FirstL()
+    while ( view.NextL() )
+        {
+        // Retrieve the current row
+        view.GetL();
+        length = view.ColLength(hmm_col);
+        checksum = view.ColUint32(hmmchecksum_col);
+        
+        // Read the acoustic model into a buffer
+        TUint8* hmmBuf = new (ELeave) TUint8[length];
+        CleanupStack::PushL(hmmBuf);
+        TPtr8 hmmPtr(hmmBuf, 0, length);
+        RDbColReadStream colReadStrm;
+       	colReadStrm.OpenLC(view, hmm_col);
+       	colReadStrm.ReadL(hmmPtr, length);
+        // Cleanup colReadStrm
+        CleanupStack::PopAndDestroy();
+        
+        if ( VerifyChecksum( hmmPtr, checksum) )
+            {
+            CSIModel* model = CSIModel::NewLC(modelID);
+            HBufC8* aAcousticModel=HBufC8::NewL(length); 
+            *aAcousticModel=hmmPtr;
+            model->SetAcousticModel(aAcousticModel);
+            modelBank->AddL((CSIModel*)model);
+            //!
+            // Cleanup aAcousticModel and hmmBuf
+            CleanupStack::Pop();
+            CleanupStack::PopAndDestroy();
+            
+            }
+        else
+            {
+            User::Leave( KErrCorrupt );
+            }
+        }
+    
+    // Keep the reference of the modelBank
+    //User::LeaveIfError(iModelBankArray.Append(modelBank));
+    // Cleanup modelBank
+    CleanupStack::Pop();
+    
+    // Cleanup view
+    CleanupStack::PopAndDestroy();
+    
+    return modelBank;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::AllAcousticModelsL
+// Loads all acoustic models within the specified model bank into a model bank
+// object, which is loaded into recognizer during recognition session.
+// -----------------------------------------------------------------------------
+//
+const CSIModelBank* CSIModelBankDB::AllAcousticModelsL( TSIModelBankID aModelBankID )
+    {
+    // Construct the table name using the provided model bank ID
+    TBuf<40> KModelBankName(KSIModelBankTable);
+    KModelBankName.AppendNumUC(aModelBankID);
+    
+    TBuf<100> KSQLStatement;
+    // Declare a literal string to hold the SQL statement
+    // SELECT  KHmmColumn, KHmmChecksumColumn FROM KModelBankName
+    _LIT(KSQLSelect1, "SELECT * ");
+    _LIT(KSQLSelect2, " FROM ");
+    
+    KSQLStatement = KSQLSelect1;
+    //	KSQLStatement.Append(KHmmColumn);
+    //	KSQLStatement.Append(KNext);
+    //	KSQLStatement.Append(KHmmChecksumColumn);
+    KSQLStatement.Append(KSQLSelect2);
+    KSQLStatement.Append(KModelBankName);
+    RDbView view;
+    CleanupClosePushL(view);
+    User::LeaveIfError(view.Prepare(iDb, TDbQuery(KSQLStatement, EDbCompareNormal)));
+    User::LeaveIfError(view.EvaluateAll());
+    
+    // Get column set for column ordinals
+    CDbColSet* columns = view.ColSetL();
+    TDbColNo hmm_col = columns->ColNo(KHmmColumn);
+    TDbColNo hmmchecksum_col = columns->ColNo(KHmmChecksumColumn);
+    delete columns;
+    
+    // Create a model bank object
+    CSIModelBank* modelBank = CSIModelBank::NewLC(aModelBankID);
+    
+    TSIModelID modelID=KModelID;
+    TInt length;
+    TInt32 checksum;
+    // After evaluation, the first call to NextL() is equivalent to FirstL()
+    while ( view.NextL() )
+        {
+        // Retrieve the current row
+        view.GetL();
+        length = view.ColLength(hmm_col);
+        checksum = view.ColUint32(hmmchecksum_col);
+        
+        // Read the acoustic model into a buffer
+        TUint8* hmmBuf = new (ELeave) TUint8[length];
+        CleanupStack::PushL(hmmBuf);
+        TPtr8 hmmPtr(hmmBuf, 0, length);
+        RDbColReadStream colReadStrm;
+       	colReadStrm.OpenLC(view, hmm_col);
+       	colReadStrm.ReadL(hmmPtr, length);
+        // Cleanup colReadStrm
+        CleanupStack::PopAndDestroy();
+
+#ifdef __SIND_HMMS_TO_FILE
+        {
+        TInt error( KErrNone );
+        RFile sampleFile; 
+        RFs fileSession; 
+        User::LeaveIfError( fileSession.Connect() );
+
+        _LIT( KCDrive,"c:\\" ); 
+        _LIT( KFileName, "data\\rec\\hmm_%08d.raw" ); 
+        _LIT( KStartOfYear, "20060101:000000.000000" ); 
+        TTime startOfYear( KStartOfYear ); 
+        TTimeIntervalSeconds secondsSince; 
+        TTime nowtime; 
+        nowtime.UniversalTime(); 
+        nowtime.SecondsFrom( startOfYear, secondsSince );
+
+        TFileName fileName; 
+        fileName.Append( KCDrive ); 
+        fileName.AppendFormat( KFileName, secondsSince.Int() ); 
+        error = sampleFile.Replace( fileSession, fileName, EFileWrite );
+        if ( !error ) 
+            {
+            TPtr8 ptr( hmmBuf, length ); 
+            ptr.SetLength( length ); 
+            sampleFile.Write( ptr );
+            sampleFile.Close();
+            }   
+        fileSession.Close();
+        }
+#endif
+        
+        if ( VerifyChecksum( hmmPtr, checksum) )
+            {
+            CSIModel* model = CSIModel::NewLC(modelID);
+            HBufC8* aAcousticModel=HBufC8::NewL(length); 
+            *aAcousticModel=hmmPtr;
+            SetAcousticModelL(aAcousticModel->Des());
+            model->SetAcousticModel(aAcousticModel);
+            modelBank->AddL((CSIModel*)model);
+            //!
+            // Cleanup aAcousticModel and hmmBuf
+            CleanupStack::Pop();
+            CleanupStack::PopAndDestroy();
+            }
+        else
+            {
+            User::Leave( KErrCorrupt );
+            }
+        }
+    
+    // Keep the reference of the modelBank
+    User::LeaveIfError(iModelBankArray.Append(modelBank));
+    // Cleanup modelBank
+    CleanupStack::Pop();
+    // Cleanup view
+    CleanupStack::PopAndDestroy();
+    
+    return modelBank;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::AllModelCountL
+// Returns the total number of models in the system (all model banks).
+// -----------------------------------------------------------------------------
+//
+TInt CSIModelBankDB::AllModelCountL()
+    {
+    TBuf<100> KSQLStatement;
+    // Declare a literal string to hold the SQL statement
+    // SELECT KCounterColumn FROM KModelBankIdTable WHERE KUsedColumn = KUsed
+    _LIT(KSQLSelect1, "SELECT ");
+    _LIT(KSQLSelect2, " FROM ");
+    _LIT(KSQLSelect3, " WHERE ");
+    
+    KSQLStatement = KSQLSelect1;
+    KSQLStatement.Append(KCounterColumn);
+    KSQLStatement.Append(KSQLSelect2);
+    KSQLStatement.Append(KModelBankIdTable);
+    KSQLStatement.Append(KSQLSelect3);
+    KSQLStatement.Append(KUsedColumn);
+    KSQLStatement.Append(KEqual);
+    KSQLStatement.AppendNum(KUsed);
+    
+    RDbView view;
+    CleanupClosePushL(view);
+    User::LeaveIfError(view.Prepare(iDb, TDbQuery(KSQLStatement, EDbCompareNormal)));
+    User::LeaveIfError(view.EvaluateAll());
+    
+    // Get column set for column ordinals
+    CDbColSet* columns = view.ColSetL();
+    
+    delete columns;
+    
+    TInt counter = 0;
+    // After evaluation, the first call to NextL() is equivalent to FirstL()
+    while ( view.NextL() )
+        {
+        // Retrieve the current row
+        view.GetL();
+        //counter += view.ColInt(counter_col);
+        //!
+        counter ++;//=view.ColInt(used_col); 
+        }
+    
+    // Cleanup view
+    CleanupStack::PopAndDestroy();
+    
+    return counter;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::CreateIDTableL
+// Creates a new model bank ID table in the database.
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::CreateIDTableL()
+    {
+    // Invoke function in the base class CSICommonDB.
+    CSICommonDB::CreateIDTableL(KModelBankIdTable, KModelBankIdColumn, KModelBankIndex);
+    };
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::CreateModelBankL
+// Creates a new model bank table in the database.
+// -----------------------------------------------------------------------------
+//
+TSIModelBankID CSIModelBankDB::CreateModelBankL( TUid aClientUid )
+    {
+    RUBY_DEBUG_BLOCK( "CSIModelBankDB::CreateModelBankL" );
+    
+    // Model bank is already exist in the 
+    RArray<TSIModelBankID> aExistModelBankIDs;
+    CleanupClosePushL( aExistModelBankIDs );
+    GetAllClientModelBankIDsL(aClientUid,aExistModelBankIDs);
+    
+    
+    if(aExistModelBankIDs.Count()>0) {
+        TSIModelBankID aExistModelBankID=aExistModelBankIDs[0];	
+        CleanupStack::PopAndDestroy( &aExistModelBankIDs );
+        return aExistModelBankID;
+        }
+    CleanupStack::PopAndDestroy( &aExistModelBankIDs );
+    
+    User::LeaveIfError( iDbSession.ReserveDriveSpace( iDrive, sizeof( CSIModelBank ) ) );
+    
+    // Generate a new model bank ID
+    TSIModelBankID modelBankID = STATIC_CAST(TSIModelBankID,CreateNewIDL(KModelBankIdTable, KModelBankIdColumn, aClientUid));
+    // Construct the table name using the new model bank ID
+    TBuf<40> KModelBankName(KSIModelBankTable);
+    KModelBankName.AppendNumUC(modelBankID);
+    // Create a table definition
+    CDbColSet* columns=CDbColSet::NewLC();
+    
+    // add the columns  
+    // 1) Binary data, 2) binary data size
+    columns->AddL(TDbCol(KHmmColumn,EDbColLongBinary));
+    columns->AddL(TDbCol(KHmmChecksumColumn,EDbColUint32));
+    
+    // Create a table
+    TInt err =iDb.CreateTable(KModelBankName,*columns);
+    
+    if ( err != KErrNone )
+        {
+        // Failed to create the table.
+        // Need to release the new ModelBank ID and leave.
+        ReleaseIdL(KModelBankIdTable, KModelBankIdColumn, modelBankID);
+        User::Leave(err);
+        }
+    
+    // cleanup the column set
+    CleanupStack::PopAndDestroy();
+    
+    // Put and empty Modelbank inside
+        {
+        //!!! Use the default model file to construct	
+        //!
+        HBufC8 *bf=NULL;		
+        bf= iDataLoader->LoadData( KModelBankPackageType,KModelBankLanguageType,KModelBankStartPos,KMaxTUint32);
+        // Modelbank file does not exist;
+        if(bf==NULL)
+            User::Leave(KErrNotFound);
+        CleanupStack::PushL(bf);
+        
+        iAcousticModelPtr.Set(bf->Des());
+        //.Set(_L8("empty"));
+        //iAcousticModelPtr=(_L8("empty"));
+        // Always 1 for each model bank
+        //TSIModelID modelID=KModelID; 
+        
+        TInt32 hmmChecksum = CalculateChecksum(iAcousticModelPtr);
+        
+        // Open model bank table
+        RDbTable dbTable;		// Provides access to table data as a rowset
+        User::LeaveIfError(dbTable.Open(iDb, KModelBankName, RDbTable::EUpdatable));
+        CleanupClosePushL(dbTable);
+        
+        // Get column set for column ordinals
+        columns = dbTable.ColSetL();
+        TDbColNo hmm_col = columns->ColNo(KHmmColumn);
+        TDbColNo hmmchecksum_col = columns->ColNo(KHmmChecksumColumn);
+        delete columns;
+        
+        // 		 No, insert new row
+        dbTable.InsertL();
+        dbTable.SetColL(hmm_col, iAcousticModelPtr);
+        
+        dbTable.SetColL(hmmchecksum_col, hmmChecksum);
+        
+        // Write the updated row
+        TRAPD(err, dbTable.PutL());
+        if( err != KErrNone )
+            {
+            // Error: cancel update
+            dbTable.Cancel();
+            dbTable.Reset();
+            User::Leave(err);
+            }
+        
+        // Cleanup bf dbTable 
+        CleanupStack::PopAndDestroy(2);
+        // Free up resources
+        Reset();
+        }
+        
+    iDbSession.FreeReservedSpace( iDrive );
+        
+    //AllAcousticModelsL(modelBankID);
+    return modelBankID;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::GetAllClientModelBankIDsL
+// This function returns all model bank IDs owned by the specified client.
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::GetAllClientModelBankIDsL( TUid aClientUid,
+                                                RArray<TSIModelBankID>& aModelBankIDs )
+    {
+    // This is a hack to get the id aligned to 4-byte boundary,
+    // for some reason this does not happen in winscw build if 
+    // TSIModelBankID is taken from stack.
+    TSIModelBankID* id = new (ELeave) TSIModelBankID;
+    CleanupStack::PushL( id );
+    
+    RArray<TUint32> ix;
+    ix.Reset();
+    GetAllClientIDsL(KModelBankIdTable, KModelBankIdColumn, aClientUid, ix);
+    for(TInt i=0;i<ix.Count();i++) 
+        {
+        *id = STATIC_CAST( TSIModelBankID, ix[i] );
+        aModelBankIDs.Append( *id );
+        }
+    ix.Close();
+    CleanupStack::PopAndDestroy( id );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::GetAllModelBankIDsL
+// This function returns all model bank IDs in the database.
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::GetAllModelBankIDsL( RArray<TSIModelBankID>& aModelBankIDs )
+    {
+    // This is a hack to get the id aligned to 4-byte boundary,
+    // for some reason this does not happen in winscw build if 
+    // TSIModelBankID is taken from stack.
+    TSIModelBankID* id = new ( ELeave ) TSIModelBankID;
+    CleanupStack::PushL( id );
+    
+    RArray<TUint32> ix;
+    ix.Reset();
+    GetAllIDsL( KModelBankIdTable, KModelBankIdColumn, ix );
+    for ( TInt i = 0; i < ix.Count(); i++ ) 
+        { 
+        *id = STATIC_CAST( TSIModelBankID, ix[i] );
+        aModelBankIDs.Append( *id );
+        }
+    ix.Close();
+    CleanupStack::PopAndDestroy( id );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::GetAllModelIDsL
+// This function returns all model IDs within the specified model bank. It's
+// expected that the client has already done allocation on aModelIDs array object.
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::GetAllModelIDsL( TSIModelBankID /*aModelBankID*/,
+                                     RArray<TSIModelID>& aModelIDs )
+    {
+    // Only one id , and it is KModelID
+    aModelIDs.Append(KModelID);	
+    }
+	
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::IsModelBankValidL
+// Checks if the specified model bank table exists in the database and also verify
+// ownership.
+// -----------------------------------------------------------------------------
+//
+TBool CSIModelBankDB::IsModelBankValidL( TUid aClientUid,
+                                         TSIModelBankID aModelBankID )
+    {
+    VerifyOwnershipL(aClientUid, KModelBankIdTable, KModelBankIndex, aModelBankID);
+    return ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::IsModelValidL
+// Checks if the specified model exists in the specified model bank table.
+// -----------------------------------------------------------------------------
+//
+TBool CSIModelBankDB::IsModelValidL( TSIModelBankID /*aModelBankID*/,
+                                     TSIModelID aModelID )
+    {
+    // Assume that ModelBankd ID is valid
+    if (aModelID==KModelID)
+        {
+        return ETrue;
+        }
+    else
+        {
+        return EFalse;
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::UpdateModelBankIfInvalidL
+// Validate the adapted model bank against ROM version and update if not valid.
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::UpdateModelBankIfInvalidL( TSIModelBankID aModelBankID )
+    {    
+    RUBY_DEBUG_BLOCK( "CSIModelBankDB::UpdateModelBankIfInvalidL" );
+    
+    const TUint KModelBankHeaderSize(20);
+    
+    HBufC8 *bf = iDataLoader->LoadData( KModelBankPackageType,
+                                        KModelBankLanguageType,
+                                        KModelBankStartPos,
+                                        KMaxTUint32 );
+    
+    if( bf == NULL )
+        {
+        // Modelbank file does not exist;
+        User::Leave( KErrNotFound );
+        }
+        
+    CleanupStack::PushL( bf );
+    
+    TPtr8 origModelPtr( bf->Des() );
+
+    // Compare phoneme definitions
+    TBool areEqual( EFalse );
+    
+    TRAPD( error, 
+        const CSIModelBank* adaptedModelBank = GetAllAcousticModelsL( aModelBankID );
+        CleanupStack::PushL( (CSIModelBank*)adaptedModelBank );
+
+        TPtrC8 adaptedModelPtr = adaptedModelBank->AtL(0).AcousticModel();
+        
+        // 1. Compare size of phoneme definition
+        TInt adaptedSize = adaptedModelPtr[18];
+        adaptedSize |= adaptedModelPtr[19] << 8;
+            
+        TInt origSize = origModelPtr[18];
+        origSize |= origModelPtr[19] << 8;
+        
+        if ( adaptedSize == origSize )
+            {
+            // 2. compare content of phoneme definitions
+            TInt size = origSize + KModelBankHeaderSize;
+            if ( Mem::Compare( origModelPtr.Ptr(), size, adaptedModelPtr.Ptr(), size ) == 0 )
+                {
+                areEqual = ETrue;
+                }
+            }
+
+        CleanupStack::PopAndDestroy( (CSIModelBank*)adaptedModelBank );
+    );
+    
+    // GetAllAcousticModelsL will leave with KErrCorrupt if checksum doesn't match
+    // This case should be handled by updating model bank
+    if ( error != KErrNone && error != KErrCorrupt )
+        {
+        User::Leave( error );
+        }
+    
+    if ( !areEqual )
+        {
+        // replace the adapted model bank with the original model bank
+        RUBY_DEBUG0("phoneme definitions changed or model bank corrupted, update models" );
+        
+        SetAcousticModelL( origModelPtr );
+        SaveModelL( aModelBankID );
+        }
+
+    CleanupStack::PopAndDestroy( bf );
+    }
+    
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::GetUtteranceDurationL
+//
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::GetUtteranceDurationL( TSIModelBankID /*aModelBankID*/, 
+                                            TSIModelID /*aModelID*/,
+                                            TTimeIntervalMicroSeconds32& /*aDuration*/ )
+    {
+    User::Leave(KErrNotSupported);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::ModelCountL
+// Returns the number of models in the specified model bank.
+// -----------------------------------------------------------------------------
+//
+TInt CSIModelBankDB::ModelCountL( TSIModelBankID /*aModelBankID*/ )
+    {
+    
+    //User::Leave(KErrNotSupported);
+    return 1;
+    // one model per modelbank by defination
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::RemoveModelBankL
+// Deletes a model bank table from the database.
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::RemoveModelBankL( TUid aClientUid,
+                                       TSIModelBankID aModelBankID )
+    {
+    VerifyOwnershipL(aClientUid, KModelBankIdTable, KModelBankIndex, aModelBankID);
+    
+    TInt diskSpace = ( ModelCountL(aModelBankID) * sizeof( CSIModel ) )
+        + sizeof( CSIModelBank );
+    User::LeaveIfError( iDbSession.ReserveDriveSpace( iDrive, diskSpace ) );
+    
+    // Construct the table name using the provided model bank ID
+    TBuf<40> KModelBankName(KSIModelBankTable);
+    KModelBankName.AppendNumUC(aModelBankID);
+    
+    TBuf<50> KSQLStatement;
+    // Declare a literal string to hold the SQL statement
+    // DROP TABLE KModelBankName
+    _LIT(KSQLDelete1, "DROP TABLE ");
+    
+    KSQLStatement = KSQLDelete1;
+    KSQLStatement.Append(KModelBankName);
+    
+    User::LeaveIfError(iDb.Execute(KSQLStatement));
+    
+    // Release the ModelBank ID
+    ReleaseIdL(KModelBankIdTable, KModelBankIdColumn, aModelBankID);
+    
+    // Cancel free disk space request
+    iDbSession.FreeReservedSpace( iDrive );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::RemoveModelL
+// Removes a model from the model bank table by marking it as "not used".
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::RemoveModelL( TUid /*aClientUid*/,
+                                   TSIModelBankID /*aModelBankID*/,
+                                   TSIModelID /*aModelID*/ )
+    {
+    User::Leave(KErrNotSupported);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::Reset
+// Deallocates the temporary memory allocated during training.
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::Reset()
+    {
+    iAcousticModelPtr.Set(0,0,0);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::Reset
+// Deallocates the temporary memory allocated during recognition.
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::ResetAndDestroy()
+    {
+    iModelBankArray.ResetAndDestroy();
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::SaveModelL
+// Saves the trained model in the temporary memory into the database.
+// -----------------------------------------------------------------------------
+//
+TSIModelID CSIModelBankDB::SaveModelL( TSIModelBankID aModelBankID )
+    {
+    if ( iAcousticModelPtr.Length() <= 0 )
+        {
+        User::Leave(KErrNotReady);
+        }
+
+    User::LeaveIfError( iDbSession.ReserveDriveSpace( iDrive, sizeof( CSIModel ) ) );
+    
+    // Always 1 for each model bank
+    TSIModelID modelID=KModelID; 
+    // Construct the table name using the provided model bank ID
+    TBuf<40> KModelBankName(KSIModelBankTable);
+    KModelBankName.AppendNumUC(aModelBankID);
+    
+    TInt32 hmmChecksum = CalculateChecksum(iAcousticModelPtr);
+    
+    // Open model bank table
+    RDbTable dbTable;		// Provides access to table data as a rowset
+    User::LeaveIfError(dbTable.Open(iDb, KModelBankName, RDbTable::EUpdatable));
+    CleanupClosePushL(dbTable);
+    
+    // Get column set for column ordinals
+    CDbColSet* columns = dbTable.ColSetL();
+    TDbColNo hmm_col = columns->ColNo(KHmmColumn);
+    TDbColNo hmmchecksum_col = columns->ColNo(KHmmChecksumColumn);
+    delete columns;
+    
+    // 		Update it
+    dbTable.FirstL(); 	
+    dbTable.UpdateL();
+    
+    dbTable.SetColL(hmm_col, iAcousticModelPtr);
+    dbTable.SetColL(hmmchecksum_col, hmmChecksum);
+    
+    // Write the updated row
+    TRAPD(err, dbTable.PutL());
+    if( err != KErrNone )
+        {
+        // Error: cancel update
+        dbTable.Cancel();
+        dbTable.Reset();
+        User::Leave(err);
+        }
+    iDbSession.FreeReservedSpace( iDrive );
+    // Cleanup dbTable
+    CleanupStack::PopAndDestroy();
+    // Free up resources
+    Reset();
+    
+    return modelID;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::SetAcousticModelL
+// Saves the acoustic model into a temporary memory during training.
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::SetAcousticModelL( const TPtr8& aAcousticModelBuf )
+    {
+    if ( aAcousticModelBuf.Length() <= 0 )
+        {
+        User::Leave(KErrNotReady);
+        }
+    
+    iAcousticModelPtr.Set(aAcousticModelBuf);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::SetUtteranceDurationL
+// Saves the utterance duration of a trained model in temporary memory during
+// training.
+// -----------------------------------------------------------------------------
+//
+void CSIModelBankDB::SetUtteranceDurationL( TInt /*aUtteranceDuration*/ )
+    {
+    User::Leave( KErrNotSupported );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::CalculateChecksum
+// Calculates a checksum value for the given buffer.
+// -----------------------------------------------------------------------------
+//
+TInt32 CSIModelBankDB::CalculateChecksum( const TPtr8& aBuf )
+    {
+    TInt32 checksum = 0;
+    TInt length = aBuf.Length();
+    
+    for( TInt i = 0; i < length; i++ )
+        {
+        checksum += aBuf[i];
+        }
+    return checksum;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIModelBankDB::VerifyChecksum
+// Verifies the checksum value for the given buffer by comparing it with the
+// provided aChecksum value.
+// -----------------------------------------------------------------------------
+//
+TBool CSIModelBankDB::VerifyChecksum( const TPtr8& aBuf,
+                                      TInt32 aChecksum )
+    {
+    TInt32 checksum = CalculateChecksum(aBuf);
+    return (checksum == aChecksum);
+    }
+
+
+// -----------------------------------------------------------------------------
+// Unit Test only
+// -----------------------------------------------------------------------------
+//
+#ifdef __CONSOLETEST__
+// Returns array of loaded model banks
+RPointerArray<CSIModelBank>& CSIModelBankDB::ModelBankArray()
+    {
+    return iModelBankArray;
+    }
+
+#endif
+
+//  End of File