// Copyright (C) 1999 Jean-Marc Valin

#include "BufferedNode.h"
#include "Buffer.h"
#include "Vector.h"
#include "vec.h"

#ifdef HAVE_VALUES_H
#include <values.h>
#endif

#ifdef HAVE_FLOAT_H
#include <float.h>
#endif

using namespace std;

namespace FD {

class TimeEntropy;

DECLARE_NODE(TimeEntropy)
/*Node
 *
 * @name TimeEntropy
 * @category DSP:Misc
 * @description Non-stationnarity (pseudo-entropy) measure across vectors (frames)
 *
 * @input_name INPUT
 * @input_type Vector<float>
 * @input_description Input vectors (frames)
 *
 * @output_name OUTPUT
 * @output_type Vector<float>
 * @output_description Value of the non-stationnarity measure (as a vector of 1 component)
 *
 * @parameter_name LOOKAHEAD
 * @parameter_type int
 * @parameter_description Maximum forward (non-causal) delay
 *
 * @parameter_name LOOKBACK
 * @parameter_type int
 * @parameter_description Maximum backward (causal) delay
 *
END*/


class TimeEntropy : public BufferedNode {
   
   int inputID;
   int outputID;

   int numberFrames;
   vector<Vector<float> *> frames;
   vector<float> min;

public:
   TimeEntropy(string nodeName, ParameterSet params)
      : BufferedNode(nodeName, params)

   {
      inputID = addInput("INPUT");
      outputID = addOutput("OUTPUT");
      

      inputsCache[inputID].lookAhead = dereference_cast<int> (parameters.get("LOOKAHEAD"));
      inputsCache[inputID].lookBack = dereference_cast<int> (parameters.get("LOOKBACK"));
      
      numberFrames=inputsCache[inputID].lookBack+inputsCache[inputID].lookAhead+1;
      frames.resize(numberFrames);
      min.resize(numberFrames);
   }


   static inline float dist (float *in1, float *in2, int length)
   {
      int i;
      float sum=0;
      for (i=0;i<length;i++)
      {
         float tmp;
         tmp=in1[i]-in2[i];
         sum += tmp*tmp;
      }
      return sum;
   }

   void calculate(int output_id, int count, Buffer &out)
   {
      Vector<float> &output = *Vector<float>::alloc(1);
      out[count] = &output;


      if (count < inputsCache[inputID].lookBack)
      {
         output[0]=0.0;
         return;
      }
      NodeInput input = inputs[inputID];

      int i, j;
      int inputLength;
      for (i = -inputsCache[inputID].lookBack, j=0; i <= inputsCache[inputID].lookAhead ; i++, j++)
      {
         //RCPtr<Vector<float> > inputValue = input.node->getOutput(input.outputID, count + i);
         ObjectRef inputValue = input.node->getOutput(input.outputID, count + i);
         //frames[j] = inputValue.get();
         frames[j] = object_ptr_cast<Vector<float> *> (inputValue);
	 inputLength = frames[j]->size();
      }      
      
      //cerr << numberFrames << " " << (*(frames[0]))[0] << " " ; 

      for (i=0;i<numberFrames;i++)
         min[i]=FLT_MAX;
      
      /*float sx[inputLength];
      float sx2[inputLength];
      for (int i=0;i<inputLength;i++)
	 sx[i]=sx2[i]=0;
      */

      for (i=0;i<numberFrames;i++)
      {
	 /*for (j=0;j<inputLength;j++)
	 {
	    sx[j] += (*frames[i])[j];
	    sx2[j] += (*frames[i])[j] * (*frames[i])[j];
	 }
	 */
	 for (j=i+1;j<numberFrames;j++)
	 {
	    float tmp = vec_dist2(&(*frames[i])[0], &(*frames[j])[0], inputLength);
	    //float tmp=dist(&(*frames[i])[0], &(*frames[j])[0], inputLength);
	    if (tmp < min[i]) min[i]=tmp;
	    if (tmp < min[j]) min[j]=tmp;
	 }
      }
      float accum=0;
      for (i=0;i<numberFrames;i++)
      {
         //cerr <<  min[i] << " ";
         accum += min[i];
      }
      output[0] = accum/numberFrames;
      //cerr << output[0] << endl;

      /*float var=0;
      for (j=0;j<inputLength;j++)
	 var += sx2[j]-sx[j]*sx[j]/numberFrames;
      output[1] = var/numberFrames/inputLength;
      */
   }

NO_ORDER_NODE_SPEEDUP(TimeEntropy)
};

}//namespace FD


syntax highlighted by Code2HTML, v. 0.9.1