internal TrajectoryModel(ref ArrayMemory memory, ref Binary binary)
        {
            //
            // Initialize attributes
            //

            this.binary = MemoryRef <Binary> .Create(ref binary);

            float sampleRate  = binary.SampleRate;
            float timeHorizon = binary.TimeHorizon;

            int trajectoryLength =
                DurationToFrames(timeHorizon * 2.0f, sampleRate);

            trajectory = memory.CreateSlice <AffineTransform>(trajectoryLength);
            for (int i = 0; i < trajectoryLength; ++i)
            {
                trajectory[i] = AffineTransform.identity;
            }

            var accumulatedIdentity =
                AccumulatedTransform.Create(
                    AffineTransform.identity, math.rcp(binary.SampleRate));

            deltaSpaceTrajectory = memory.CreateSlice <AccumulatedTransform>(trajectoryLength * 2);
            for (int i = 0; i < trajectoryLength * 2; ++i)
            {
                deltaSpaceTrajectory[i] = accumulatedIdentity;
            }

            Assert.IsTrue(trajectoryLength == TrajectoryLength);
        }
        internal void Update(AffineTransform worldRootTransform, AffineTransform deltaTransform, float deltaTime)
        {
            NativeSlice <AffineTransform> trajectory = Array;

            int trajectoryLength     = TrajectoryLength;
            int halfTrajectoryLength = trajectoryLength / 2;

            //
            // Since the trajectory is relative to the world root transform
            // and the synthesizer is adding 'deltaTransform' we need
            // to account for this by inverse transforming the
            // character space trajectory transforms.
            //

            var inverseQ = math.normalize(
                Missing.conjugate(deltaTransform.q));

            for (int i = halfTrajectoryLength; i < trajectoryLength; ++i)
            {
                var transform = trajectory[i];
                transform.t =
                    Missing.rotateVector(
                        inverseQ, transform.t);
                transform.q = math.normalize(
                    math.mul(inverseQ, transform.q));
                trajectory[i] = transform;
            }

            //
            // Update past trajectory
            //

            for (int i = deltaSpaceTrajectory.Length - 1; i > 0; --i)
            {
                deltaSpaceTrajectory[i] = deltaSpaceTrajectory[i - 1];
            }

            var accumulatedTransform = deltaSpaceTrajectory[1].transform * deltaTransform;

            accumulatedTransform.q = math.normalize(accumulatedTransform.q);

            deltaSpaceTrajectory[0] =
                AccumulatedTransform.Create(
                    accumulatedTransform, deltaTime);

            var referenceTransform = deltaSpaceTrajectory[0].transform;

            float sampleTimeInSeconds = 0.0f;

            float inverseSampleRate = Missing.recip(Binary.SampleRate);

            int numTransforms = deltaSpaceTrajectory.Length;

            var sampler = SubSampler.Create();

            for (int i = halfTrajectoryLength - 1; i >= 0; --i)
            {
                sampleTimeInSeconds += inverseSampleRate;

                var deltaTransformAtSampleRate =
                    sampler.SampleAt(deltaSpaceTrajectory,
                                     sampleTimeInSeconds);

                trajectory[i] =
                    referenceTransform.inverseTimes(
                        deltaTransformAtSampleRate);
            }
        }