#ifndef cmProcObj_h
#define cmProcObj_h

#ifdef __cplusplus
extern "C" {
#endif

  /*

    The first field in all objects must be an cmObj record.

    p* cmProcAlloc(c, p*, initParam0, initParam1, .... ) 

    1) All processors must be generated by a call to cmProcAlloc().
    2) If p is non-NULL then it is a pointer to a statically allocated proc which is processed by the call and returned as the result.
    3) The primary job of this function is to zero the body of the object and setup the proc's cmObj field.
    4) All arguments other than the cmContext and static pointer are init. params. and should be optional.
    5) If the first init param is non-NULL then cmProcInit() is called internally. Therefore if the first init param
    is valid so must all the others.
    6) All embedded objects must be alloc'd in this function by an explicity call to their cmXXXAlloc() function.
    7) The first call in cmProcAlloc() is to cmObjAlloc().
    8) There is no way to know the state of the static object passed to cmProcAlloc() and so the object is 
    always assumed to be uninitialized.

    cmProcFree( c, p** )     

    1) All processors must be eventually freed with a call to cmProcFree().
    2) This function begins by calling cmProcFinal().
    3) All embedded objects must be free'd in this function by an explicit call to their cmXXXFree() function.
    4) All dynamically allocated memory must be freed in this function().
    5) The cmObj field indicates if the memory held by the object body needs to be freed or not (if it was statically alloc'd). 
    6) The last call in cmProcFree() is to cmObjFree().


    cmProcInit( c, p*, ... ) 

    1) Setup a previously alloc'd or init'd processor.
    2) This function always begins by calling cmProcFinal().
    3) Any dynamically allocated memory should be allocated with a call to cmMemResize().
    4) Any embedded objects must be init'd by an explic call to their cmXXXInit().


    cmProcFinal(c, p* );     

    1) This function is intended as a place to restore an object to its pre-init state.
    2) This function is called automatically at the beginning of cmProcInit() and cmProcFree().
    3) Dynamically allocated memory does NOT need to freed in final if the cmMemResize() function is used in init.
    4) Embedded objects do NOT need to be finalized here since they will be finalized by calls to there own init functions  in cmProcInit().
    5) In general there should be very little to do in this function.


  */

  // constants
  enum
  {
    // semitones per octave (length of the chroma feature vector)
    kStPerOctave      = 12,  

    // count of bands in the equal loudness contour table
    // used for sone calc. (length of the sones feature vector)
    kEqualLoudBandCnt = 15,

    kTonalSpaceDimCnt = 6
  };


  //------------------------------------------------------------------------------------------------------------

  struct cmCtx_str;

  enum
  {
    kDynObjFl = 0x01
  };

  typedef struct
  {
    unsigned          flags;
    cmErr_t           err;
    struct cmCtx_str* ctx;
  } cmObj;

  void* _cmObjAlloc( void* p, const char* label, struct cmCtx_str* c, unsigned objByteCnt );
  void  _cmObjFree(  void** pp, cmObj* op );

  // Allocate, zero, and setup the embedded cmObj field for an empty object.
#define cmObjAlloc( type, ctx, p ) (type*)(_cmObjAlloc(p,#type,ctx,sizeof(type)))

  // if pp is  non-NULL then *pp is NULL on return
  //#define cmObjFree(  pp ) _cmObjFree((void**)pp, pp==NULL ? NULL : (cmObj*)(*pp) )
#define cmObjFree( pp ) _cmObjFree( (void**)(pp), (cmObj*)(*(pp)) )

#define cmArgAssertRC   (0x80000001)
#define cmSystemErrorRC (0x80000002)  // use strerror() to get the system error 
#define cmEofRC         (0x80000003)
#define cmSingularMtxRC (0x80000004)
#define cmSubSysFailRC  (0x80000005)
#define cmInvalidArgRC  (0x80000006)

  //------------------------------------------------------------------------------------------------------------
  // Macro to allow embedded objects to be freed without having to explicitely 
  // define a pointer.
#define cmObjFreeStatic( func, type, ref ) do{ type* __p=&(ref); func(&__p); }while(0)


  //------------------------------------------------------------------------------------------------------------
  typedef struct cmCtx_str
  { 
    cmObj               obj;
    cmLHeapH_t          lhH;
    cmSymTblH_t         stH;
  } cmCtx;

  struct cmFeatFile;

  // set p to NULL to dynamically allocate the object
  cmCtx*            cmCtxAlloc( cmCtx* p, cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH );
  cmRC_t            cmCtxFree(  cmCtx** pp );
  cmRC_t            cmCtxInit(  cmCtx* c,  cmRpt_t* rpt, cmLHeapH_t lhH, cmSymTblH_t stH );
  cmRC_t            cmCtxFinal( cmCtx* c );

  cmRC_t            cmCtxPrint( cmCtx* c, const char* fmt, ... );


  // a runtime resource aquisition failed (e.g. file open failed, read failed, ... )
  cmRC_t            cmCtxRtCondition(   cmObj* p, unsigned code, const char* fmt, ... );

  // a 
  cmRC_t            cmCtxRtAssertFailed( cmObj* p, unsigned code, const char* fmt, ... );

  //------------------------------------------------------------------------------------------------------------

  typedef struct cmMtxFile
  {
    cmObj     obj;
    cmChar_t* fn;
    FILE*     fp;
  
  } cmMtxFile;

  // Create a text file and write a row of values on each call to cmMtxFileXXXExec().
  cmMtxFile*  cmMtxFileAlloc(cmCtx* c, cmMtxFile*  p, const char* fn );
  cmRC_t      cmMtxFileFree(           cmMtxFile** p );
  cmRC_t      cmMtxFileCreate(         cmMtxFile*  p, const char* fn );
  cmRC_t      cmMtxFileClose(          cmMtxFile*  p );
  cmRC_t      cmMtxFileFloatExec(      cmMtxFile*  p, const float*        inPtr, unsigned inCnt, unsigned inStride );
  cmRC_t      cmMtxFileDoubleExec(     cmMtxFile*  p, const double*       inPtr, unsigned inCnt, unsigned inStride );
  cmRC_t      cmMtxFileComplexExec(    cmMtxFile*  p, const cmComplexR_t* inPtr, unsigned inCnt, unsigned inStride );

#if CM_FLOAT_SMP==1
#define cmMtxFileSmpExec(f,p,n)    cmMtxFileFloatExec((f),(p),(n),1)
#define cmMtxFileSmpExecN(f,p,n,s) cmMtxFileFloatExec((f),(p),(n),(s))
#else
#define cmMtxFileSmpExec(f,p,n)    cmMtxFileDoubleExec((f),(p),(n),1)
#define cmMtxFileSmpExecN(f,p,n,s) cmMtxFileDoubleExec((f),(p),(n),(s))
#endif

#if CM_FLOAT_REAL==1
#define cmMtxFileRealExec(f,p,n)    cmMtxFileFloatExec((f),(p),(n),1)
#define cmMtxFileRealExecN(f,p,n,s) cmMtxFileFloatExec((f),(p),(n),(s))
#else
#define cmMtxFileRealExec(f,p,n)    cmMtxFileDoubleExec((f),(p),(n),1)
#define cmMtxFileRealExecN(f,p,n,s) cmMtxFileDoubleExec((f),(p),(n),(s))
#endif


#ifdef __cplusplus
}
#endif

#endif
