javauis/amms_qt/ammscontrol/audio3D/src/cammsorientationcontrolgroup.cpp
changeset 23 98ccebc37403
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/amms_qt/ammscontrol/audio3D/src/cammsorientationcontrolgroup.cpp	Fri May 14 15:47:24 2010 +0300
@@ -0,0 +1,600 @@
+/*
+* Copyright (c) 2005-2007 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:  Group for orientation controls
+*
+*/
+
+
+// INCLUDE FILES
+#include <logger.h>
+#include <e32math.h>
+#include "cammsorientationcontrolgroup.h"
+#include "cammsorientationcontrol.h"
+#include "ammsutil.h"
+
+
+// CONSTANTS
+namespace
+{
+// since orientation vectors consist of integers rather than real values,
+// normalized vectors have to be multiplied by a large constant to keep
+// adequate precision
+const TInt KAMMSAxisMultiplier = 1000;
+
+// Some calculations are done with real values and then rounded to integers.
+// Rounding may cause loss of precision. KAMMSMaxOrientationErrorPercentage
+// tells how much error (in percentages) is acceptable when rounding values.
+const TInt KAMMSMaxOrientationErrorPercentage = 5;
+}
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::NewLC
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+CAMMSOrientationControlGroup* CAMMSOrientationControlGroup::NewLC()
+{
+    CAMMSOrientationControlGroup* self =
+        new(ELeave) CAMMSOrientationControlGroup;
+
+    CleanupStack::PushL(self);
+    self->ConstructL();
+
+    return self;
+
+}
+
+// Destructor
+CAMMSOrientationControlGroup::~CAMMSOrientationControlGroup()
+{
+}
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::OrientationVectorsL
+// Gets the orientation of the object using two vectors
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+void CAMMSOrientationControlGroup::OrientationVectorsL(
+    TInt aOrientation[ KAMMSTwoVectorComponents ])
+{
+    // If the orientation was set by using "front" and "above" vectors,
+    // return "front" and "up" vectors.
+    if (iCommited.iOrientationVector)
+    {
+        // Get "up" vector.
+        TInt upVector[ KAMMSVectorComponents ];
+        GetUpVectorL(iCommited, upVector);
+
+        // Return the "front" and "up" vectors.
+        for (TInt i = 0; i < KAMMSVectorComponents; i ++)
+        {
+            aOrientation[ i ] = iCommited.iOrientation[ i ];
+            aOrientation[ i + KAMMSVectorComponents ] = upVector[ i ];
+        }
+    }
+    // If the orientation was set by using angles, convert set angles
+    // to "front" and "up" vectors.
+    else
+    {
+        // Start rotation from these axis vectors.
+        TReal xAxisVector[ KAMMSVectorComponents ] = { 1, 0, 0 };
+        TReal yAxisVector[ KAMMSVectorComponents ] = { 0, 1, 0 };
+        TReal zAxisVector[ KAMMSVectorComponents ] = { 0, 0, 1 };
+
+        // Result axis vectors after rotation.
+        TReal xAxisVector2[ KAMMSVectorComponents ];
+        TReal yAxisVector2[ KAMMSVectorComponents ];
+        TReal zAxisVector2[ KAMMSVectorComponents ];
+
+        // rotate round y axis
+        AMMSUtil::RotateVectorL(zAxisVector, yAxisVector,
+                                iCommited.iOrientation[ EHeading ], zAxisVector2);
+        AMMSUtil::RotateVectorL(xAxisVector, yAxisVector,
+                                iCommited.iOrientation[ EHeading ], xAxisVector2);
+
+        // rotate round x axis
+        AMMSUtil::RotateVectorL(yAxisVector, xAxisVector2,
+                                iCommited.iOrientation[ EPitch ], yAxisVector2);
+        AMMSUtil::RotateVectorL(zAxisVector2, xAxisVector2,
+                                iCommited.iOrientation[ EPitch ], zAxisVector);
+
+        // rotate round z axis
+        AMMSUtil::RotateVectorL(yAxisVector2, zAxisVector,
+                                iCommited.iOrientation[ ERoll ], yAxisVector);
+
+        // round and save "front" vector to the given parameter
+        TReal roundedValue;
+        for (TInt i = 0; i < KAMMSVectorComponents; i++)
+        {
+            User::LeaveIfError(Math::Round(roundedValue, zAxisVector[ i ] *    // CSI: 2 Wrong index means implementation error #
+                                           KAMMSAxisMultiplier, 0));
+            // "front" vector is opposite to z-axis
+            aOrientation[ i ] = -(TInt)roundedValue;    // CSI: 2 Wrong index means implementation error #
+        }
+
+        // round and save "up" vector to the given parameter
+        for (TInt e = 0; e < KAMMSVectorComponents; e++)
+        {
+            User::LeaveIfError(Math::Round(roundedValue, yAxisVector[ e ] *    // CSI: 2 Wrong index means implementation error #
+                                           KAMMSAxisMultiplier, 0));
+            aOrientation[ e + KAMMSVectorComponents ] = (TInt)roundedValue;    // CSI: 2 Wrong index means implementation error #
+        }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::SetOrientationL
+// Turns the object to the new orientation
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+void CAMMSOrientationControlGroup::SetOrientationL(
+    TInt aHeading,
+    TInt aPitch,
+    TInt aRoll)
+{
+    iUncommited.iOrientation[ EHeading ]    = aHeading;
+    iUncommited.iOrientation[ EPitch ]      = aPitch;
+    iUncommited.iOrientation[ ERoll ]       = aRoll;
+    iUncommited.iOrientationVector = EFalse;
+
+    UpdateL(EOrientation);
+}
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::SetOrientationVectorsL
+// Turns the object to the new orientation
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+void CAMMSOrientationControlGroup::SetOrientationVectorsL(
+    TInt aFrontVector[ KAMMSVectorComponents ],
+    TInt aAboveVector[ KAMMSVectorComponents ])
+{
+    for (TInt i = 0; i < KAMMSVectorComponents; i++)
+    {
+        iUncommited.iOrientation[ i ] = aFrontVector[ i ];
+        iUncommited.iOrientation[ i + KAMMSVectorComponents ] =
+            aAboveVector[ i ];
+    }
+    iUncommited.iOrientationVector = ETrue;
+
+    UpdateL(EOrientation);
+}
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::TypeSafeControl
+// Gets control. Ownership is not tranferred.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+CAMMSOrientationControl*
+CAMMSOrientationControlGroup::TypeSafeControl(TInt aIndex) const
+{
+    return static_cast<CAMMSOrientationControl*>(Control(aIndex));
+}
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::GetUpVectorL
+// Calculates and returns "up" vector by using "front" and "above" vectors.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+void CAMMSOrientationControlGroup::GetUpVectorL(
+    TVariables& aVariables,
+    TInt aUpVector[ KAMMSVectorComponents ])
+{
+    __ASSERT_DEBUG(aVariables.iOrientationVector, User::Invariant());
+
+    // Calculate first "right" vector and then "up" vector.
+    // The "right" vector is calculated as cross product of the "front"
+    // and "above" vectors.
+    // The "up" vector is calculated as cross product of the "right"
+    // and "front" vectors.
+
+    TReal frontVector[ KAMMSVectorComponents ] =
+    {
+        aVariables.iOrientation[ EFrontX ],
+        aVariables.iOrientation[ EFrontY ],
+        aVariables.iOrientation[ EFrontZ ]
+    };
+
+    TReal aboveVector[ KAMMSVectorComponents ] =
+    {
+        aVariables.iOrientation[ EAboveX ],
+        aVariables.iOrientation[ EAboveY ],
+        aVariables.iOrientation[ EAboveZ ]
+    };
+
+    TReal rightVector[ KAMMSVectorComponents ];
+
+    TReal vectorLength = Min(AMMSUtil::VectorLengthL(frontVector),
+                             (TReal)KMaxTInt);
+
+    // Perform cross product with unit vectors.
+    AMMSUtil::ConvertToUnitVectorL(frontVector);
+    AMMSUtil::ConvertToUnitVectorL(aboveVector);
+
+    TReal upVector[ KAMMSVectorComponents ];
+
+    AMMSUtil::CrossProduct(frontVector, aboveVector, rightVector);
+    AMMSUtil::CrossProduct(rightVector, frontVector, upVector);
+
+    AMMSUtil::ConvertToUnitVectorL(upVector);
+
+    // Multiply the unit vector so that the result "up" vector has the same
+    // length as the "front" vector.
+
+    AMMSUtil::MultiplyVector(upVector, vectorLength);
+
+    // Round the vector.
+    AMMSUtil::RoundVectorL(upVector, aUpVector);
+
+    // Check the rounding error. If it is too high, multiply the original
+    // vector before rounding.
+    if (!AMMSUtil::AreVectorsSimilar(upVector,
+                                     aUpVector,
+                                     KAMMSMaxOrientationErrorPercentage))
+    {
+        AMMSUtil::MultiplyVector(upVector, (TReal)KAMMSAxisMultiplier);
+
+        // Accept this multiplied vector only if it can be fit into TInt.
+        if ((AMMSUtil::MinVectorComponent(upVector) >= KMinTInt) &&
+                (AMMSUtil::MaxVectorComponent(upVector) <= KMaxTInt))
+        {
+            AMMSUtil::RoundVectorL(upVector, aUpVector);
+        }
+    }
+}
+
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::ConvertOrientationToAnglesL
+// Converts orientation from vectors to angles.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+void CAMMSOrientationControlGroup::ConvertOrientationToAnglesL(
+    TVariables& aVariables,
+    TInt aSphericalOrientation[ KAMMSVectorComponents ])
+{
+    // Get vector for y-axis.
+    TInt temp[ KAMMSVectorComponents ];
+    GetUpVectorL(aVariables, temp);
+    TReal yAxisVector[] = { temp[ EComponentX ], temp[ EComponentY ],
+                            temp[ EComponentZ ]
+                          };
+
+    AMMSUtil::ConvertToUnitVectorL(yAxisVector);
+
+
+    // Get vector for z-axis.
+    TReal frontVector[] =
+    {
+        aVariables.iOrientation[ EFrontX ],
+        aVariables.iOrientation[ EFrontY ],
+        aVariables.iOrientation[ EFrontZ ]
+    };
+
+    // Z-axis is opposite to the front vector.
+    AMMSUtil::ConvertToUnitVectorL(frontVector);
+    TReal zAxisVector[ KAMMSVectorComponents ] =
+    {
+        -frontVector[ EFrontX ],
+        -frontVector[ EFrontY ],
+        -frontVector[ EFrontZ ]
+    };
+
+
+    // Calculate orientation vector for the x-axis.
+    // The vector is calculated as cross product of the y-
+    // and z-axis vectors.
+    TReal xAxisVector[ KAMMSVectorComponents ];
+
+    AMMSUtil::CrossProduct(yAxisVector, zAxisVector, xAxisVector);
+    AMMSUtil::ConvertToUnitVectorL(xAxisVector);
+
+
+    // First rotate the object coordinate axels so that the object y-axel is
+    // parallel to the global y-axis (this gives us roll and pitch angles).
+    // Then rotate the object coordinate axels so that x- and z-axels are
+    // parallel to the global x- and z-axels, respectively (this gives the
+    // heading).
+
+
+    // Calculate how much the axels should be rotated round the z-axis.
+    TReal rotateRollDeg = CalculatePartialRotationL(yAxisVector, zAxisVector, EComponentY);
+
+    AMMSUtil::RotateVectorL(xAxisVector, zAxisVector, rotateRollDeg, xAxisVector);
+    AMMSUtil::RotateVectorL(yAxisVector, zAxisVector, rotateRollDeg, yAxisVector);
+
+
+    // Calculate how much the axels should be rotated round the x-axis.
+    TReal rotatePitchDeg = CalculatePartialRotationL(yAxisVector, xAxisVector, EComponentY);
+
+    AMMSUtil::RotateVectorL(yAxisVector, xAxisVector, rotatePitchDeg, yAxisVector);
+    AMMSUtil::RotateVectorL(zAxisVector, xAxisVector, rotatePitchDeg, zAxisVector);
+
+    // Calculate how much the axels should be rotated round the y-axis.
+    TReal rotateHeadingDeg = CalculatePartialRotationL(xAxisVector, yAxisVector, EComponentX);
+
+    TReal resultAngles[] = { -rotateHeadingDeg,
+                             -rotatePitchDeg,
+                             -rotateRollDeg
+                           };
+
+    AMMSUtil::RoundVectorL(resultAngles, aSphericalOrientation);
+}
+
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::CalculatePartialRotationL
+// Calculates how much the given vector should be rotated around the given
+// rotation vector so that the value of the specified vector component is
+// maximized.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+TReal CAMMSOrientationControlGroup::CalculatePartialRotationL(
+    TReal aVector[ KAMMSVectorComponents ],
+    TReal aRotationAxelVector[ KAMMSVectorComponents ],
+    TInt aMaximizeComponent)
+{
+    __ASSERT_DEBUG((aMaximizeComponent >= EComponentX) &&
+                   (aMaximizeComponent <= EComponentZ),
+                   User::Invariant());
+
+    TReal x = aRotationAxelVector[ EComponentX ];
+    TReal y = aRotationAxelVector[ EComponentY ];
+    TReal z = aRotationAxelVector[ EComponentZ ];
+
+    // calculate the length of the axis vector
+    TReal lengthSquare = x * x + y * y + z * z;
+    TReal length;
+    User::LeaveIfError(Math::Sqrt(length, lengthSquare));
+
+    // check that the vector is long enough
+    __ASSERT_DEBUG(length > 0, User::Invariant());
+
+
+    // Find out the components that are tried to set 0.
+    TInt zeroComponents[ KAMMSVectorComponents - 1 ];
+    TInt counter = 0;
+
+    for (TInt i = 0; i < KAMMSVectorComponents; i++)
+    {
+        if (i != aMaximizeComponent)
+        {
+            zeroComponents[ counter ] = i;
+            counter++;
+        }
+    }
+
+    // normalize the axis vector
+    x = x / length;
+    y = y / length;
+    z = z / length;
+
+    // calculate some help variables
+    TReal xx = x * x;
+    TReal yy = y * y;
+    TReal zz = z * z;
+
+    TReal x2 = aVector[ EComponentX ];
+    TReal y2 = aVector[ EComponentY ];
+    TReal z2 = aVector[ EComponentZ ];
+
+    TReal xx2 = x * x2;
+    TReal yy2 = y * y2;
+    TReal zz2 = z * z2;
+
+    TReal xxx2 = xx * x2;
+    TReal yyy2 = yy * y2;
+    TReal zzz2 = zz * z2;
+
+    TReal constants[] =
+    {
+        xxx2 + x *(yy2 + zz2),
+        yyy2 + y *(xx2 + zz2),
+        zzz2 + z *(xx2 + yy2)
+    };
+
+    TReal cosMultipliers[] =
+    {
+        constants[ EComponentX ] - x2,
+        constants[ EComponentY ] - y2,
+        constants[ EComponentZ ] - z2
+    };
+
+    TReal sinMultipliers[] =
+    {
+        z * y2 - y * z2,
+        x * z2 - z * x2,
+        y * x2 - x * y2
+    };
+
+    // The angles where some component of the vector is zero.
+    TReal zeroAngles[ 4 ];  // CSI: 47 Two components may have zero points in 4 angles. #
+    TInt angleCounter = 0;
+
+    // Find rotation angles that makes (at least) one of the vector components
+    // to be 0 (however, dismiss the component to be maximized).
+    for (int i = 0; i < KAMMSVectorComponents - 1; i++)
+    {
+        TInt componentIndex = zeroComponents[ i ];
+
+        TReal cosMultiplier = cosMultipliers[ componentIndex ];
+        TReal sinMultiplier = sinMultipliers[ componentIndex ];
+
+        TReal angleDeg = 0;
+
+        // If both multipliers are zero, this vector is parallel or opposite
+        // to the target vector. Thus, no need to calculate the angle.
+        if ((cosMultiplier != 0) ||
+                (sinMultiplier != 0))
+        {
+            // Calculate the angle that makes this vector element to be 0.
+            TReal temp = cosMultiplier * cosMultiplier +
+                         sinMultiplier * sinMultiplier;
+
+            TReal divider = 0;
+            User::LeaveIfError(Math::Sqrt(divider, temp));
+
+            TReal arcTan = 0;
+            User::LeaveIfError(
+                Math::ATan(arcTan, sinMultiplier, cosMultiplier));
+
+            TReal arcCos = 0;
+            User::LeaveIfError(Math::ACos(
+                                   arcCos, constants[ i ] / divider));    // CSI: 2 Wrong index means implementation error #
+
+            TReal angleRad = arcCos + arcTan;
+
+            // Save the angle in degrees.
+            angleDeg = angleRad * 180 / KPi;  // CSI: 47 Value 180 means 180 degrees #
+        }
+
+        zeroAngles[ angleCounter ] = angleDeg;
+
+        zeroAngles[ angleCounter + 1 ] = angleDeg + 180; // CSI: 47 Save also the opposite direction (+ 180 degrees) #
+
+        angleCounter += 2;  // CSI: 47 Two angles have been found #
+    }
+
+
+    // Find the angle that gives the maximum value for the component
+    // to be maximized.
+    TReal maxValue = -0xFFFF;
+    TInt maxIndex = KErrNotFound;
+
+    for (TInt i = 0; i < angleCounter; i++)
+    {
+        // Rotate the original vector.
+        TReal rotatedVector[ KAMMSVectorComponents ];
+
+        AMMSUtil::RotateVectorL(aVector, aRotationAxelVector,
+                                zeroAngles[ i ], rotatedVector);   // CSI: 2 Wrong index means implementation error #
+
+        // Check the value of the component that should be maximized.
+        TReal value = rotatedVector[ aMaximizeComponent ];
+
+        if (value > maxValue)
+        {
+            maxValue = value;
+            maxIndex = i;
+        }
+    }
+
+    return zeroAngles[ maxIndex ];
+}
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::ClassName
+// Returns class name that identifies this control group.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+const TDesC16& CAMMSOrientationControlGroup::ClassName()
+{
+    return KAMMSOrientationControlClassName;
+}
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::CommitL
+// Transfers all the pending parameters to the audio processing system.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+void CAMMSOrientationControlGroup::CommitL(TInt aCommit)
+{
+    if (aCommit & EOrientation)
+    {
+        TInt controls = ControlCount();
+
+        if (controls > 0)
+        {
+            TInt angleVector[] =
+            {
+                iUncommited.iOrientation[ EHeading ],
+                iUncommited.iOrientation[ EPitch ],
+                iUncommited.iOrientation[ ERoll ]
+            };
+
+            // If the orientation was given in vectors, convert
+            // the vectors to angles because at the moment the Effect API
+            // can handle only angles.
+            if (iUncommited.iOrientationVector)
+            {
+                ConvertOrientationToAnglesL(iUncommited, angleVector);
+            }
+
+            for (TInt i = 0; i < controls; i++)
+            {
+                CAMMSOrientationControl* control = TypeSafeControl(i);
+
+                control->SetOrientationL(
+                    angleVector[ EHeading ],
+                    angleVector[ EPitch ],
+                    angleVector[ ERoll ]);
+            }
+        }
+
+        iCommited = iUncommited;
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::NotifyPlayerAddedL
+// Called by when a new player is added
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+void CAMMSOrientationControlGroup::NotifyPlayerAddedL(
+    CMMAPlayer* aPlayer,
+    CMMAControl* aControl)
+{
+    CAMMSAudio3DControlGroup::NotifyPlayerAddedL(aPlayer, aControl);
+
+    CAMMSOrientationControl* control =
+        static_cast<CAMMSOrientationControl*>(aControl);
+
+    // set the current parameters
+    if (iCommited.iOrientationVector)
+    {
+        TInt angleVector[ KAMMSVectorComponents ];
+
+        ConvertOrientationToAnglesL(iCommited, angleVector);
+
+        control->SetOrientationL(
+            angleVector[ EHeading ],
+            angleVector[ EPitch ],
+            angleVector[ ERoll ]);
+    }
+    else
+    {
+        control->SetOrientationL(
+            iCommited.iOrientation[ EHeading ],
+            iCommited.iOrientation[ EPitch ],
+            iCommited.iOrientation[ ERoll ]);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CAMMSOrientationControlGroup::CAMMSOrientationControlGroup
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+CAMMSOrientationControlGroup::CAMMSOrientationControlGroup()
+        : CAMMSAudio3DControlGroup(KAMMSOrientationControl)
+{
+    // Default orientation is:
+    // heading = 0
+    // pitch = 0
+    // roll = 0
+    iCommited.iOrientationVector = EFalse;
+}
+
+//  End of File