/* VASP modular - vector assembling signal processor / objects for Max/MSP and PD Copyright (c) 2002 Thomas Grill (xovo@gmx.net) For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file, "license.txt," in this distribution. */ #include "main.h" #include "ops_rearr.h" #include "oploop.h" #include "oppermute.h" /*! \brief vasp shift or rotation \todo units for shift */ Vasp *VaspOp::m_shift(OpParam &p,CVasp &src,const Argument &arg,CVasp *dst,BL shift,BL symm) { Vasp *ret = NULL; RVecBlock *vecs = GetRVecs(p.opname,src,dst); if(vecs) { if(arg.IsList() && arg.GetList().Count() >= 1 && flext::CanbeFloat(arg.GetList()[0])) { // shift length p.sh.sh = flext::GetAFloat(arg.GetList()[0]); } else { post("%s - invalid argument -> set to 0",p.opname); p.sh.sh = 0; } ret = DoOp(vecs,shift?VecOp::d_shift:VecOp::d_rot,p,symm); delete vecs; } return ret; } /*! \brief shift buffer */ BL VecOp::d_shift(OpParam &p) { if(p.ovrlap) { post("%s - cannot operate on overlapped vectors",p.opname); return false; } I ish = (I)p.sh.sh; if(p.sh.sh != ish) { // integer shift // requires interpolation post("non-integer shift not implemented - truncating to integer"); p.sh.sh = ish; } p.SkipOddMiddle(); if(p.symm == 1) ish = -ish; I aish = abs(ish); if(aish > p.frames) aish = ish = p.frames; I i,cnt = p.frames-aish; const S *sd = p.rsdt-ish*p.rss; S *dd = p.rddt; if(ish > 0) { sd += (p.frames-1)*p.rss,dd += (p.frames-1)*p.rds; p.rss = -p.rss,p.rds = -p.rds; } // do shift if(cnt > 0) { if(p.rss == 1 && p.rds == 1) _DE_LOOP(i,cnt, ( *(dd++) = *(sd++) ) ) else if(p.rss == -1 && p.rds == -1) _DE_LOOP(i,cnt, ( *(dd--) = *(sd--) ) ) else _DE_LOOP(i,cnt, ( *dd = *sd,sd += p.rss,dd += p.rds ) ) } // fill spaces if(p.sh.fill) { S vfill = p.sh.fill == 1?0:dd[-p.rds]; I aish = abs(ish); if(p.rds == 1) _DE_LOOP(i,aish, ( *(dd++) = vfill ) ) else if(p.rds == -1) _DE_LOOP(i,aish, ( *(dd--) = vfill ) ) else _DE_LOOP(i,aish, ( *dd = vfill,dd += p.rds ) ) } return true; } class vasp_shift: public vasp_anyop { FLEXT_HEADER_S(vasp_shift,vasp_anyop,Setup) public: vasp_shift(I argc,const t_atom *argv): vasp_anyop(argc,argv,VASP_ARG_I(0),true), fill(xsf_zero) {} static V Setup(t_classid c) { FLEXT_CADDATTR_VAR1_E(c,"fill",fill); } enum xs_fill { xsf__ = -1, // don't change xsf_none = 0,xsf_zero,xsf_edge }; virtual Vasp *do_shift(OpParam &p) { CVasp cdst(dst),cref(ref); return VaspOp::m_shift(p,cref,arg,&cdst); } virtual Vasp *tx_work(const Argument &arg) { OpParam p(thisName(),0); p.sh.fill = (I)fill; Vasp *ret = do_shift(p); return ret; } virtual V m_help() { post("%s - Shifts buffer data",thisName()); } protected: xs_fill fill; private: FLEXT_ATTRVAR_E(fill,xs_fill) }; VASP_LIB_V("vasp.shift",vasp_shift) class vasp_xshift: public vasp_shift { FLEXT_HEADER(vasp_xshift,vasp_shift) public: vasp_xshift(I argc,const t_atom *argv): vasp_shift(argc,argv) {} virtual Vasp *do_shift(OpParam &p) { CVasp cdst(dst),cref(ref); return VaspOp::m_xshift(p,cref,arg,&cdst); } virtual V m_help() { post("%s - Shifts buffer data symmetrically (in two halves)",thisName()); } }; VASP_LIB_V("vasp.xshift",vasp_xshift) inline int rotation(int ij, int n,OpParam &p) { return (ij+n-p.sh.ish)%n; } #define ROTBLOCK 1024 /*! \brief rotate buffer \todo implement temporary storage for faster transformation (use abstract permute algorithm) */ BL VecOp::d_rot(OpParam &p) { if(p.ovrlap) { post("%s - cannot operate on overlapped vectors",p.opname); return false; } p.sh.ish = (I)p.sh.sh; if(p.sh.sh != p.sh.ish) { // requires interpolation post("%s - non-integer shift not implemented - truncating to integer",p.opname); } p.SkipOddMiddle(); p.sh.ish = p.sh.ish%p.frames; if(p.symm == 1) p.sh.ish = -p.sh.ish; /* if(p.frames >= ROTBLOCK) { //use temporary space; S *tmp = new S[ROTBLOCK]; delete[] tmp; } else */ PERMUTATION(S,1,p,rotation); return true; } VASP_ANYOP("vasp.rot",rot,0,true,VASP_ARG_I(0),"Rotates buffer data") VASP_ANYOP("vasp.xrot",xrot,0,true,VASP_ARG_I(0),"Rotates buffer data symmetrically (in two halves)") /*! \brief mirror buffer */ BL VecOp::d_mirr(OpParam &p) { if(p.ovrlap) { post("%s - cannot operate on overlapped vectors",p.opname); return false; } p.SkipOddMiddle(); if(p.rsdt == p.rddt) { S *dl = p.rddt,*du = p.rddt+(p.frames-1)*p.rds; register S t; _DE_WHILE(dl < du, ( t = *dl, *dl = *du, *du = t, dl += p.rds,du -= p.rds ) ) } else { I i; const S *ds = p.rsdt; S *dd = p.rddt+(p.frames-1)*p.rds; _DE_LOOP(i,p.frames, ( *dd = *ds,ds += p.rss,dd -= p.rds ) ) } return true; } /*! \brief vasp mirror */ Vasp *VaspOp::m_mirr(OpParam &p,CVasp &src,CVasp *dst,BL symm) { Vasp *ret = NULL; RVecBlock *vecs = GetRVecs(p.opname,src,dst); if(vecs) { ret = DoOp(vecs,VecOp::d_mirr,p,symm); delete vecs; } return ret; } VASP_UNARY("vasp.mirr",mirr,true,"Mirrors buffer data") VASP_UNARY("vasp.xmirr",xmirr,true,"Mirrors buffer data symmetrically (in two halves)")