diff options
Diffstat (limited to 'externals/grill/xsample/source')
-rw-r--r-- | externals/grill/xsample/source/groove.cpp | 788 | ||||
-rw-r--r-- | externals/grill/xsample/source/inter.cpp | 128 | ||||
-rwxr-xr-x | externals/grill/xsample/source/inter.h | 511 | ||||
-rw-r--r-- | externals/grill/xsample/source/main.cpp | 244 | ||||
-rw-r--r-- | externals/grill/xsample/source/main.h | 306 | ||||
-rw-r--r-- | externals/grill/xsample/source/play.cpp | 86 | ||||
-rw-r--r-- | externals/grill/xsample/source/prefix.h | 1 | ||||
-rw-r--r-- | externals/grill/xsample/source/record.cpp | 336 |
8 files changed, 1241 insertions, 1159 deletions
diff --git a/externals/grill/xsample/source/groove.cpp b/externals/grill/xsample/source/groove.cpp index 341d241f..507cf349 100644 --- a/externals/grill/xsample/source/groove.cpp +++ b/externals/grill/xsample/source/groove.cpp @@ -1,11 +1,9 @@ /* - xsample - extended sample objects for Max/MSP and pd (pure data) -Copyright (c) 2001-2004 Thomas Grill (xovo@gmx.net) +Copyright (c) 2001-2005 Thomas Grill (gr@grrrr.org) For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file, "license.txt," in this distribution. - */ #include "main.h" @@ -26,110 +24,96 @@ class xgroove: FLEXT_HEADER_S(xgroove,xinter,setup) public: - xgroove(I argc,const t_atom *argv); - ~xgroove(); - - virtual BL Init(); - - virtual V m_help(); - virtual V m_print(); - - virtual V m_units(xs_unit mode = xsu__); + xgroove(int argc,const t_atom *argv); + virtual ~xgroove(); - virtual BL m_reset(); + void m_pos(float pos) + { + setpos(s2u?pos/s2u:0); + Update(xsc_pos,true); + } - virtual V m_pos(F pos); - inline V m_posmod(F pos) { setposmod(pos?pos/s2u:0); } // motivated by Tim Blechmann - virtual V m_all(); - virtual V m_min(F mn); - virtual V m_max(F mx); + inline void m_posmod(float pos) { setposmod(pos?pos/s2u:0); } // motivated by Tim Blechmann - V ms_xfade(I xf); - V ms_xshape(I sh); + inline void mg_pos(float &v) const { v = curpos*s2u; } - V ms_xzone(F xz); - V mg_xzone(F &xz) { xz = _xzone*s2u; } - - enum xs_loop { - xsl__ = -1, // don't change - xsl_once = 0,xsl_loop,xsl_bidir - }; enum xs_fade { - xsf__ = -1, // don't change xsf_keeplooppos = 0,xsf_keeplooplen,xsf_keepfade,xsf_inside }; enum xs_shape { - xss__ = -1, // don't change xss_lin = 0,xss_qsine,xss_hsine }; - V m_loop(xs_loop lp = xsl__); + + void ms_xfade(int xf) + { + xfade = (xs_fade)xf; + Update(xsc_fade,true); + } + + void ms_xshape(int sh); + + void ms_xzone(float xz); + void mg_xzone(float &xz) { xz = _xzone*s2u; } + + void m_loop(xs_loop lp) + { + loopmode = lp,bidir = 1; + Update(xsc_loop,true); + } protected: - xs_loop loopmode; - D curpos; // in samples - I bidir; + double curpos; // in samples + float bidir; // +1 or -1 - F _xzone,xzone; - L znsmin,znsmax; + float _xzone,xzone; + long znsmin,znsmax; xs_fade xfade; - I xshape; - S **znbuf; - S *znpos,*znmul,*znidx; - I pblksz; + int xshape; + t_sample **znbuf; + t_sample *znpos,*znmul,*znidx; + int pblksz; - inline V outputmin() { ToOutFloat(outchns+1,curmin*s2u); } - inline V outputmax() { ToOutFloat(outchns+2,curmax*s2u); } - - inline V setpos(D pos) + inline void setpos(double pos) { if(pos < znsmin) curpos = znsmin; else if(pos > znsmax) curpos = znsmax; else curpos = pos; } - inline V setposmod(D pos) + inline void setposmod(double pos) { - D p = pos-znsmin; + double p = pos-znsmin; if(p >= 0) curpos = znsmin+fmod(p,znsmax-znsmin); else curpos = znsmax+fmod(p,znsmax-znsmin); } - inline V mg_pos(F &v) const { v = curpos*s2u; } + virtual void DoReset(); + virtual void DoUpdate(unsigned int flags); + + virtual void m_help(); + virtual void m_print(); + virtual void m_signal(int n,t_sample *const *in,t_sample *const *out); private: - static V setup(t_classid c); + static void setup(t_classid c); - virtual V s_dsp(); + //! return true if something has changed + bool do_xzone(); DEFSIGFUN(s_pos_off); DEFSIGFUN(s_pos_once); - DEFSIGFUN(s_pos_c_once); - DEFSIGFUN(s_pos_a_once); DEFSIGFUN(s_pos_loop); - DEFSIGFUN(s_pos_c_loop); - DEFSIGFUN(s_pos_a_loop); DEFSIGFUN(s_pos_loopzn); DEFSIGFUN(s_pos_bidir); DEFSIGCALL(posfun); - DEFSTCALL(zonefun); - V do_xzone(); - - virtual V m_signal(I n,S *const *in,S *const *out) - { - if(bufchk()) - posfun(n,in,out); - else - zerofun(n,in,out); - } - - static S fade_lin[],fade_qsine[],fade_hsine[]; + static t_sample fade_lin[],fade_qsine[],fade_hsine[]; FLEXT_CALLBACK_F(m_pos) FLEXT_CALLBACK_F(m_posmod) @@ -137,6 +121,8 @@ private: FLEXT_CALLBACK_F(m_max) FLEXT_CALLBACK(m_all) + FLEXT_CALLSET_E(m_loop,xs_loop) + FLEXT_CALLSET_I(ms_xfade) FLEXT_ATTRGET_I(xfade) FLEXT_CALLSET_I(ms_xshape) @@ -147,23 +133,21 @@ private: FLEXT_CALLVAR_F(mg_pos,m_pos) FLEXT_CALLSET_F(m_min) FLEXT_CALLSET_F(m_max) - FLEXT_CALLSET_E(m_loop,xs_loop) - FLEXT_ATTRGET_E(loopmode,xs_loop) }; FLEXT_LIB_DSP_V("xgroove~",xgroove) -S xgroove::fade_lin[XZONE_TABLE+1]; -S xgroove::fade_qsine[XZONE_TABLE+1]; -S xgroove::fade_hsine[XZONE_TABLE+1]; +t_sample xgroove::fade_lin[XZONE_TABLE+1]; +t_sample xgroove::fade_qsine[XZONE_TABLE+1]; +t_sample xgroove::fade_hsine[XZONE_TABLE+1]; #ifndef PI #define PI 3.14159265358979f #endif -V xgroove::setup(t_classid c) +void xgroove::setup(t_classid c) { DefineHelp(c,"xgroove~"); @@ -196,14 +180,14 @@ V xgroove::setup(t_classid c) } } -xgroove::xgroove(I argc,const t_atom *argv): - loopmode(xsl_loop),curpos(0),bidir(1), +xgroove::xgroove(int argc,const t_atom *argv): + curpos(0),bidir(1), _xzone(0),xzone(0), xfade(xsf_keeplooppos),xshape(xss_lin), znpos(NULL),znmul(NULL),znidx(NULL), pblksz(0) { - I argi = 0; + int argi = 0; #if FLEXT_SYS == FLEXT_SYS_MAX if(argc > argi && CanbeInt(argv[argi])) { outchns = GetAInt(argv[argi]); @@ -211,11 +195,9 @@ xgroove::xgroove(I argc,const t_atom *argv): } #endif - if(argc > argi && IsSymbol(argv[argi])) { - buf = new buffer(GetSymbol(argv[argi]),true); - + buf.Set(GetSymbol(argv[argi]),true); argi++; #if FLEXT_SYS == FLEXT_SYS_MAX @@ -227,14 +209,12 @@ xgroove::xgroove(I argc,const t_atom *argv): } #endif } - else - buf = new buffer(NULL,true); - AddInSignal("Signal of playing speed"); // speed signal + AddInSignal("Signal of playing speed"); // speed signal AddInFloat("Starting point"); // min play pos AddInFloat("Ending point"); // max play pos - for(I ci = 0; ci < outchns; ++ci) { - C tmp[30]; + for(int ci = 0; ci < outchns; ++ci) { + char tmp[30]; STD::sprintf(tmp,"Audio signal channel %i",ci+1); AddOutSignal(tmp); // output } @@ -244,16 +224,17 @@ xgroove::xgroove(I argc,const t_atom *argv): AddOutBang("Bang on loop end/rollover"); // loop bang // don't know vector size yet -> wait for m_dsp - znbuf = new S *[outchns]; - for(I i = 0; i < outchns; ++i) znbuf[i] = NULL; + znbuf = new t_sample *[outchns]; + for(int i = 0; i < outchns; ++i) znbuf[i] = NULL; - ms_xshape(xshape); + // initialize crossfade shape + ms_xshape(xshape); } xgroove::~xgroove() { if(znbuf) { - for(I i = 0; i < outchns; ++i) if(znbuf[i]) FreeAligned(znbuf[i]); + for(int i = 0; i < outchns; ++i) if(znbuf[i]) FreeAligned(znbuf[i]); delete[] znbuf; } @@ -261,80 +242,22 @@ xgroove::~xgroove() if(znidx) FreeAligned(znidx); } -BL xgroove::Init() -{ - if(xinter::Init()) { - m_reset(); - return true; - } - else - return false; -} - -V xgroove::m_units(xs_unit mode) -{ - xsample::m_units(mode); // calls bufchk() - - m_sclmode(); // calls bufchk() again.... \todo optimize that!! - outputmin(); - outputmax(); -} - -V xgroove::m_min(F mn) -{ - xsample::m_min(mn); - m_pos(curpos*s2u); -// do_xzone(); - s_dsp(); - outputmin(); -} - -V xgroove::m_max(F mx) -{ - xsample::m_max(mx); - m_pos(curpos*s2u); -// do_xzone(); - s_dsp(); - outputmax(); -} - -V xgroove::m_pos(F pos) -{ - setpos(pos && s2u?pos/s2u:0); -} - -V xgroove::m_all() -{ - xsample::m_all(); -// do_xzone(); - s_dsp(); - outputmin(); - outputmax(); -} - -BL xgroove::m_reset() +void xgroove::DoReset() { + xinter::DoReset(); curpos = 0; bidir = 1; - return xsample::m_reset(); } -V xgroove::ms_xfade(I xf) +void xgroove::ms_xzone(float xz) { - xfade = (xs_fade)xf; - // do_xzone(); - s_dsp(); -} + ChkBuffer(true); -V xgroove::ms_xzone(F xz) -{ - bufchk(); - _xzone = xz < 0 || !s2u?0:xz/s2u; -// do_xzone(); - s_dsp(); + _xzone = (xz < 0 || !s2u)?0:xz/s2u; + Update(xsc_fade,true); } -V xgroove::ms_xshape(I sh) +void xgroove::ms_xshape(int sh) { xshape = (xs_shape)sh; switch(xshape) { @@ -349,105 +272,10 @@ V xgroove::ms_xshape(I sh) // no need to recalc the fade zone here } -V xgroove::do_xzone() -{ - // \todo do we really need this? - if(!s2u) return; // this can happen if DSP is off - - xzone = _xzone; // make a copy for changing it - - if(xfade == xsf_inside) { - // fade zone goes inside the loop -> loop becomes shorter - - // \todo what about round-off? - const L maxfd = (curmax-curmin)/2; - if(xzone > maxfd) xzone = maxfd; - - znsmin = curmin,znsmax = curmax; - } - else if(xfade == xsf_keepfade) { - // try to keep fade zone - // change of loop bounds may happen - // restrict xzone to half of buffer - const L maxfd = buf->Frames()/2; - if(xzone > maxfd) xzone = maxfd; - - // \todo what about round-off? - znsmin = curmin-(L)(xzone/2); - znsmax = curmax+(L)(xzone/2); - - // widen loop if xzone doesn't fit into it - // \todo check formula - L lack = (L)ceil((xzone*2-(znsmax-znsmin))/2); - if(lack > 0) znsmin -= lack,znsmax += lack; - - // check buffer limits and shift bounds if necessary - if(znsmin < 0) { - znsmax -= znsmin; - znsmin = 0; - } - if(znsmax > buf->Frames()) - znsmax = buf->Frames(); - } - else if(xfade == xsf_keeplooplen) { - // try to keep loop length - // shifting of loop bounds may happen - - const L plen = curmax-curmin; - if(xzone > plen) xzone = plen; - const L maxfd = buf->Frames()-plen; - if(xzone > maxfd) xzone = maxfd; - - // \todo what about round-off? - znsmin = curmin-(L)(xzone/2); - znsmax = curmax+(L)(xzone/2); - - // check buffer limits and shift bounds if necessary - // both cases can't happen because of xzone having been limited above - if(znsmin < 0) { - znsmax -= znsmin; - znsmin = 0; - } - else if(znsmax > buf->Frames()) { - znsmin -= znsmax-buf->Frames(); - znsmax = buf->Frames(); - } - } - else if(xfade == xsf_keeplooppos) { - // try to keep loop position and length - - // restrict fade zone to maximum length - const L plen = curmax-curmin; - if(xzone > plen) xzone = plen; - - // \todo what about round-off? - znsmin = curmin-(L)(xzone/2); - znsmax = curmax+(L)(xzone/2); - - L ovr = znsmax-buf->Frames(); - if(-znsmin > ovr) ovr = -znsmin; - if(ovr > 0) { - znsmin += ovr; - znsmax -= ovr; - xzone -= ovr*2; - } - } - - FLEXT_ASSERT(znsmin <= znsmax && (znsmax-znsmin) >= xzone*2); -} - -V xgroove::m_loop(xs_loop lp) -{ - loopmode = lp; - bidir = 1; - s_dsp(); -} - - -V xgroove::s_pos_off(I n,S *const *invecs,S *const *outvecs) +void xgroove::s_pos_off(int n,t_sample *const *invecs,t_sample *const *outvecs) { - S *pos = outvecs[outchns]; + t_sample *pos = outvecs[outchns]; SetSamples(pos,n,curpos); @@ -456,19 +284,19 @@ V xgroove::s_pos_off(I n,S *const *invecs,S *const *outvecs) SetSamples(pos,n,scale(curpos)); } -V xgroove::s_pos_once(I n,S *const *invecs,S *const *outvecs) +void xgroove::s_pos_once(int n,t_sample *const *invecs,t_sample *const *outvecs) { - const S *speed = invecs[0]; - S *pos = outvecs[outchns]; - BL lpbang = false; + const t_sample *speed = invecs[0]; + t_sample *pos = outvecs[outchns]; + bool lpbang = false; - const D smin = curmin,smax = curmax,plen = smax-smin; + const double smin = curmin,smax = curmax,plen = smax-smin; - if(buf && plen > 0) { - register D o = curpos; + if(plen > 0) { + register double o = curpos; - for(I i = 0; i < n; ++i) { - const S spd = speed[i]; // must be first because the vector is reused for output! + for(int i = 0; i < n; ++i) { + const t_sample spd = speed[i]; // must be first because the vector is reused for output! if(!(o < smax)) { o = smax; lpbang = true; } else if(o < smin) { o = smin; lpbang = true; } @@ -489,66 +317,24 @@ V xgroove::s_pos_once(I n,S *const *invecs,S *const *outvecs) if(lpbang) ToOutBang(outchns+3); } -// \TODO optimize that for spd = const! -V xgroove::s_pos_c_once(I n,S *const *invecs,S *const *outvecs) +void xgroove::s_pos_loop(int n,t_sample *const *invecs,t_sample *const *outvecs) { - const S spd = *invecs[0]; - S *pos = outvecs[outchns]; - BL lpbang = false; - - const D smin = curmin,smax = curmax,plen = smax-smin; - - if(buf && plen > 0) { - register D o = curpos; - - for(I i = 0; i < n; ++i) { - if(!(o < smax)) { o = smax; lpbang = true; } - else if(o < smin) { o = smin; lpbang = true; } - - pos[i] = o; - o += spd; - } - // normalize and store current playing position - setpos(o); - - playfun(n,&pos,outvecs); - - arrscale(n,pos,pos); - } - else - s_pos_off(n,invecs,outvecs); - - if(lpbang) ToOutBang(outchns+3); -} - -V xgroove::s_pos_a_once(I n,S *const *invecs,S *const *outvecs) -{ - const S *speed = invecs[0]; - if(speed[0] == speed[n-1]) - // assume constant speed - s_pos_c_once(n,invecs,outvecs); - else - s_pos_once(n,invecs,outvecs); -} - -V xgroove::s_pos_loop(I n,S *const *invecs,S *const *outvecs) -{ - const S *speed = invecs[0]; - S *pos = outvecs[outchns]; - BL lpbang = false; + const t_sample *speed = invecs[0]; + t_sample *pos = outvecs[outchns]; + bool lpbang = false; #ifdef __VEC__ // prefetch cache vec_dst(speed,GetPrefetchConstant(1,n>>2,0),0); #endif - const D smin = curmin,smax = curmax,plen = smax-smin; + const double smin = curmin,smax = curmax,plen = smax-smin; - if(buf && plen > 0) { - register D o = curpos; + if(plen > 0) { + register double o = curpos; - for(I i = 0; i < n; ++i) { - const S spd = speed[i]; // must be first because the vector is reused for output! + for(int i = 0; i < n; ++i) { + const t_sample spd = speed[i]; // must be first because the vector is reused for output! // normalize offset if(!(o < smax)) { // faster than o >= smax @@ -580,82 +366,33 @@ V xgroove::s_pos_loop(I n,S *const *invecs,S *const *outvecs) if(lpbang) ToOutBang(outchns+3); } -// \TODO optimize that for spd = const! -V xgroove::s_pos_c_loop(I n,S *const *invecs,S *const *outvecs) +void xgroove::s_pos_loopzn(int n,t_sample *const *invecs,t_sample *const *outvecs) { - const S spd = *invecs[0]; - S *pos = outvecs[outchns]; - BL lpbang = false; - - const D smin = curmin,smax = curmax,plen = smax-smin; - - if(buf && plen > 0) { - register D o = curpos; - - for(I i = 0; i < n; ++i) { - // normalize offset - if(!(o < smax)) { // faster than o >= smax - o = fmod(o-smin,plen)+smin; - lpbang = true; - } - else if(o < smin) { - o = fmod(o-smin,plen)+smax; - lpbang = true; - } - - pos[i] = o; - o += spd; - } - // normalize and store current playing position - setpos(o); - - playfun(n,&pos,outvecs); - - arrscale(n,pos,pos); - } - else - s_pos_off(n,invecs,outvecs); - - if(lpbang) ToOutBang(outchns+3); -} - -V xgroove::s_pos_a_loop(I n,S *const *invecs,S *const *outvecs) -{ - const S *speed = invecs[0]; - if(speed[0] == speed[n-1]) - // assume constant speed - s_pos_c_loop(n,invecs,outvecs); - else - s_pos_loop(n,invecs,outvecs); -} - -V xgroove::s_pos_loopzn(I n,S *const *invecs,S *const *outvecs) -{ - const S *speed = invecs[0]; - S *pos = outvecs[outchns]; - BL lpbang = false; + const t_sample *speed = invecs[0]; + t_sample *pos = outvecs[outchns]; + bool lpbang = false; FLEXT_ASSERT(xzone); - const F xz = xzone,xf = (F)XZONE_TABLE/xz; + const float xz = xzone,xf = (float)XZONE_TABLE/xz; // adapt the playing bounds to the current cross-fade zone - const L smin = znsmin,smax = znsmax,plen = smax-smin; + const long smin = znsmin,smax = znsmax,plen = smax-smin; // temporary storage - const L cmin = curmin,cmax = curmax; + const long cmin = curmin,cmax = curmax; // hack -> set curmin/curmax to loop extremes so that sampling functions (playfun) don't get confused curmin = smin,curmax = smax; - if(buf && plen > 0) { - BL inzn = false; - register D o = curpos; + if(plen > 0) { + bool inzn = false; + register double o = curpos; // calculate inner cross-fade boundaries - const D lmin = smin+xz,lmax = smax-xz,lsh = lmax-lmin+xz; - const D lmin2 = lmin-xz/2,lmax2 = lmax+xz/2; + const double lmin = smin+xz,lmax = smax-xz,lsh = lmax-lmin+xz; + const double lmin2 = lmin-xz/2,lmax2 = lmax+xz/2; - for(I i = 0; i < n; ++i) { + for(int i = 0; i < n; ++i) { // normalize offset if(o < smin) { o = fmod(o-smin,plen)+smax; @@ -666,9 +403,8 @@ V xgroove::s_pos_loopzn(I n,S *const *invecs,S *const *outvecs) lpbang = true; } -#if 1 if(o < lmin) { - register F inp; + register float inp; if(o < lmin2) { // in first half of early cross-fade zone // this happens only once, then the offset is normalized to the end @@ -678,20 +414,20 @@ V xgroove::s_pos_loopzn(I n,S *const *invecs,S *const *outvecs) // now lmax <= o <= lmax2 lpbang = true; - inp = xz-(F)(o-lmax); // 0 <= inp < xz + inp = xz-(float)(o-lmax); // 0 <= inp < xz znpos[i] = lmin-inp; } else { // in second half of early cross-fade zone - inp = xz+(F)(o-lmin); // 0 <= inp < xz + inp = xz+(float)(o-lmin); // 0 <= inp < xz znpos[i] = lmax+inp; } znidx[i] = inp*xf; inzn = true; } else if(!(o < lmax)) { - register F inp; + register float inp; if(!(o < lmax2)) { // in second half of late cross-fade zone // this happens only once, then the offset is normalized to the beginning @@ -700,12 +436,12 @@ V xgroove::s_pos_loopzn(I n,S *const *invecs,S *const *outvecs) // now lmin2 <= o <= lmin lpbang = true; - inp = xz+(F)(o-lmin); // 0 <= inp < xz + inp = xz+(float)(o-lmin); // 0 <= inp < xz znpos[i] = lmax+inp; } else { // in first half of late cross-fade zone - inp = xz-(F)(o-lmax); // 0 <= inp < xz + inp = xz-(float)(o-lmax); // 0 <= inp < xz znpos[i] = lmin-inp; } znidx[i] = inp*xf; @@ -714,30 +450,9 @@ V xgroove::s_pos_loopzn(I n,S *const *invecs,S *const *outvecs) else znidx[i] = XZONE_TABLE,znpos[i] = 0; - const S spd = speed[i]; // must be first because the vector is reused for output! + const t_sample spd = speed[i]; // must be first because the vector is reused for output! pos[i] = o; o += spd; -#else - if(o >= lmax) { - o -= lsh; - lpbang = true; - } - - if(o < lmin) { - register F inp = (F)(o-smin); // 0 <= inp < xz - znpos[i] = lmax+inp; - znidx[i] = inp*xf; - inzn = true; - } - else { - znpos[i] = 0; - znidx[i] = XZONE_TABLE; - } - - const S spd = speed[i]; // must be first because the vector is reused for output! - pos[i] = o; - o += spd; -#endif } // normalize and store current playing position @@ -759,11 +474,11 @@ V xgroove::s_pos_loopzn(I n,S *const *invecs,S *const *outvecs) arrscale(n,znidx,znpos,XZONE_TABLE,-1); // calculate fade coefficients by sampling from the fade curve - zonefun(znmul,0,XZONE_TABLE+1,n,1,1,&znidx,&znidx); - zonefun(znmul,0,XZONE_TABLE+1,n,1,1,&znpos,&znpos); + zonefun(znmul,0,XZONE_TABLE+1,n,1,1,&znidx,&znidx,false); + zonefun(znmul,0,XZONE_TABLE+1,n,1,1,&znpos,&znpos,false); // mix voices for all channels - for(I o = 0; o < outchns; ++o) { + for(int o = 0; o < outchns; ++o) { MulSamples(outvecs[o],outvecs[o],znidx,n); MulSamples(znbuf[o],znbuf[o],znpos,n); AddSamples(outvecs[o],outvecs[o],znbuf[o],n); @@ -778,29 +493,30 @@ V xgroove::s_pos_loopzn(I n,S *const *invecs,S *const *outvecs) if(lpbang) ToOutBang(outchns+3); } -V xgroove::s_pos_bidir(I n,S *const *invecs,S *const *outvecs) +void xgroove::s_pos_bidir(int n,t_sample *const *invecs,t_sample *const *outvecs) { - const S *speed = invecs[0]; - S *pos = outvecs[outchns]; - BL lpbang = false; + const t_sample *speed = invecs[0]; + t_sample *pos = outvecs[outchns]; + bool lpbang = false; - const I smin = curmin,smax = curmax,plen = smax-smin; + const int smin = curmin,smax = curmax,plen = smax-smin; - if(buf && plen > 0) { - register D o = curpos; - register F bd = bidir; + if(plen > 0) { + register double o = curpos; + register float bd = bidir; - for(I i = 0; i < n; ++i) { - const S spd = speed[i]; // must be first because the vector is reused for output! + for(int i = 0; i < n; ++i) { + const t_sample spd = speed[i]; // must be first because the vector is reused for output! // normalize offset + // \todo at the moment fmod doesn't take bidirectionality into account!! if(!(o < smax)) { - o = smax-fmod(o-smin,plen); // mirror the position at smax + o = smax-fmod(o-smax,plen); // mirror the position at smax bd = -bd; lpbang = true; } else if(o < smin) { - o = smin-fmod(o-smin,plen); // mirror the position at smin + o = smin+fmod(smin-o,plen); // mirror the position at smin bd = -bd; lpbang = true; } @@ -811,79 +527,202 @@ V xgroove::s_pos_bidir(I n,S *const *invecs,S *const *outvecs) // normalize and store current playing position setpos(o); - bidir = (I)bd; + bidir = bd; playfun(n,&pos,outvecs); arrscale(n,pos,pos); } - else + else s_pos_off(n,invecs,outvecs); if(lpbang) ToOutBang(outchns+3); } +void xgroove::m_signal(int n,t_sample *const *in,t_sample *const *out) +{ + int ret = ChkBuffer(true); + + if(ret) { + FLEXT_ASSERT(buf.Valid()); + + const lock_t l = Lock(); + posfun(n,in,out); + Unlock(l); + + Refresh(); + } + else + zerofun(n,in,out); +} + -V xgroove::s_dsp() +void xgroove::DoUpdate(unsigned int flags) { - if(doplay) { - // xzone might not be set yet (is done in do_xzone() ) - do_xzone(); // recalculate (s2u may have been 0 before) - - switch(loopmode) { - case xsl_once: - SETSIGFUN(posfun,SIGFUN(s_pos_once)); - break; - case xsl_loop: - if(xzone > 0) { - const I blksz = Blocksize(); - - if(pblksz != blksz) { - for(I o = 0; o < outchns; ++o) { - if(znbuf[o]) FreeAligned(znbuf[o]); - znbuf[o] = (S *)NewAligned(blksz*sizeof(S)); - } - - if(znpos) FreeAligned(znpos); - znpos = (S *)NewAligned(blksz*sizeof(S)); - if(znidx) FreeAligned(znidx); - znidx = (S *)NewAligned(blksz*sizeof(S)); - - pblksz = blksz; - } + xinter::DoUpdate(flags); + + if(flags&xsc_range) { + // output new range + ToOutFloat(outchns+1,curmin*s2u); + ToOutFloat(outchns+2,curmax*s2u); + } + + if(flags&(xsc_fade|xsc_range)) + if(do_xzone()) flags |= xsc_play; + + if(flags&(xsc_pos|xsc_range)) + // normalize position + setpos(curpos); + + // loop zone must already be set + if(flags&xsc_play) { + if(doplay) { + switch(loopmode) { + case xsl_once: + SETSIGFUN(posfun,SIGFUN(s_pos_once)); + break; + case xsl_loop: + if(xzone > 0) { + const int blksz = Blocksize(); + + if(pblksz != blksz) { + for(int o = 0; o < outchns; ++o) { + if(znbuf[o]) FreeAligned(znbuf[o]); + znbuf[o] = (t_sample *)NewAligned(blksz*sizeof(t_sample)); + } + + if(znpos) FreeAligned(znpos); + znpos = (t_sample *)NewAligned(blksz*sizeof(t_sample)); + if(znidx) FreeAligned(znidx); + znidx = (t_sample *)NewAligned(blksz*sizeof(t_sample)); + + pblksz = blksz; + } + + SETSIGFUN(posfun,SIGFUN(s_pos_loopzn)); + + // linear interpolation should be just ok for fade zone, no? + switch(outchns) { + case 1: SETSTFUN(zonefun,TMPLSTF(st_play2,1,1)); break; + case 2: SETSTFUN(zonefun,TMPLSTF(st_play2,1,2)); break; + case 4: SETSTFUN(zonefun,TMPLSTF(st_play2,1,4)); break; + default: SETSTFUN(zonefun,TMPLSTF(st_play2,1,-1)); + } + } + else + SETSIGFUN(posfun,SIGFUN(s_pos_loop)); + break; + case xsl_bidir: + SETSIGFUN(posfun,SIGFUN(s_pos_bidir)); + break; + default: ; // just to prevent warning + } + } + else + SETSIGFUN(posfun,SIGFUN(s_pos_off)); + } +} - SETSIGFUN(posfun,SIGFUN(s_pos_loopzn)); +bool xgroove::do_xzone() +{ + // \todo do we really need this? + if(!s2u) return false; // this can happen if DSP is off - // linear interpolation should be just ok for fade zone, no? - switch(outchns) { - case 1: SETSTFUN(zonefun,TMPLSTF(st_play2,1,1)); break; - case 2: SETSTFUN(zonefun,TMPLSTF(st_play2,1,2)); break; - case 4: SETSTFUN(zonefun,TMPLSTF(st_play2,1,4)); break; - default: SETSTFUN(zonefun,TMPLSTF(st_play2,1,-1)); - } - } - else - SETSIGFUN(posfun,SIGFUN(s_pos_loop)); - break; - case xsl_bidir: - SETSIGFUN(posfun,SIGFUN(s_pos_bidir)); - break; - default: ; // just to prevent warning + const long frames = buf.Frames(); + if(!frames) return false; + + xzone = _xzone; // make a copy for changing it + + if(xfade == xsf_inside) { + // fade zone goes inside the loop -> loop becomes shorter + + // \todo what about round-off? + const long maxfd = (curmax-curmin)/2; + if(xzone > maxfd) xzone = maxfd; + + znsmin = curmin,znsmax = curmax; + } + else if(xfade == xsf_keepfade) { + // try to keep fade zone + // change of loop bounds may happen + + // restrict xzone to half of buffer + const long maxfd = frames/2; + if(xzone > maxfd) xzone = maxfd; + + // \todo what about round-off? + const long hzone = CASTINT<long>(xzone/2.f); + znsmin = curmin-hzone; + znsmax = curmax+hzone; + + // widen loop if xzone doesn't fit into it + // \todo check formula + long lack = CASTINT<long>(ceil((xzone*2.f-(znsmax-znsmin))/2.f)); + if(lack > 0) znsmin -= lack,znsmax += lack; + + // check buffer limits and shift bounds if necessary + if(znsmin < 0) { + znsmax -= znsmin; + znsmin = 0; } + if(znsmax > frames) + znsmax = frames; } - else - SETSIGFUN(posfun,SIGFUN(s_pos_off)); - xinter::s_dsp(); -} + else if(xfade == xsf_keeplooplen) { + // try to keep loop length + // shifting of loop bounds may happen + const long plen = curmax-curmin; + if(xzone > plen) xzone = plen; + const long maxfd = frames-plen; + if(xzone > maxfd) xzone = maxfd; + // \todo what about round-off? + const long hzone = CASTINT<long>(xzone/2.f); + znsmin = curmin-hzone; + znsmax = curmax+hzone; + + // check buffer limits and shift bounds if necessary + // both cases can't happen because of xzone having been limited above + if(znsmin < 0) { + znsmax -= znsmin; + znsmin = 0; + } + else if(znsmax > frames) { + znsmin -= znsmax-frames; + znsmax = frames; + } + } + else if(xfade == xsf_keeplooppos) { + // try to keep loop position and length + + // restrict fade zone to maximum length + const long plen = curmax-curmin; + if(xzone > plen) xzone = plen; -V xgroove::m_help() + // \todo what about round-off? + const long hzone = CASTINT<long>(xzone/2.f); + znsmin = curmin-hzone; + znsmax = curmax+hzone; + + long ovr = znsmax-frames; + if(-znsmin > ovr) ovr = -znsmin; + if(ovr > 0) { + znsmin += ovr; + znsmax -= ovr; + xzone -= ovr*2; + } + } + + FLEXT_ASSERT(znsmin <= znsmax && (znsmax-znsmin) >= xzone*2.f); + + return true; +} + + +void xgroove::m_help() { post("%s - part of xsample objects, version " XSAMPLE_VERSION,thisName()); -#ifdef FLEXT_DEBUG - post("compiled on " __DATE__ " " __TIME__); -#endif - post("(C) Thomas Grill, 2001-2004"); + post("(C) Thomas Grill, 2001-2005"); #if FLEXT_SYS == FLEXT_SYS_MAX post("Arguments: %s [channels=1] [buffer]",thisName()); #else @@ -915,18 +754,17 @@ V xgroove::m_help() post(""); } -V xgroove::m_print() +void xgroove::m_print() { - static const C *sclmode_txt[] = {"units","units in loop","buffer","loop"}; - static const C *interp_txt[] = {"off","4-point","linear"}; - static const C *loop_txt[] = {"once","looping","bidir"}; + static const char *sclmode_txt[] = {"units","units in loop","buffer","loop"}; + static const char *interp_txt[] = {"off","4-point","linear"}; + static const char *loop_txt[] = {"once","looping","bidir"}; // print all current settings post("%s - current settings:",thisName()); - post("bufname = '%s', length = %.3f, channels = %i",buf->Name(),(F)(buf->Frames()*s2u),buf->Channels()); - post("out channels = %i, frames/unit = %.3f, scale mode = %s",outchns,(F)(1./s2u),sclmode_txt[sclmode]); - post("loop = %s, interpolation = %s",loop_txt[(I)loopmode],interp_txt[interp >= xsi_none && interp <= xsi_lin?interp:xsi_none]); - post("loop crossfade zone = %.3f",(F)(xzone*s2u)); + post("bufname = '%s', length = %.3f, channels = %i",buf.Name(),(float)(buf.Frames()*s2u),buf.Channels()); + post("out channels = %i, frames/unit = %.3f, scale mode = %s",outchns,(float)(1./s2u),sclmode_txt[sclmode]); + post("loop = %s, interpolation = %s",loop_txt[(int)loopmode],interp_txt[interp >= xsi_none && interp <= xsi_lin?interp:xsi_none]); + post("loop crossfade zone = %.3f",(float)(xzone*s2u)); post(""); } - diff --git a/externals/grill/xsample/source/inter.cpp b/externals/grill/xsample/source/inter.cpp index fe63fce8..418726fc 100644 --- a/externals/grill/xsample/source/inter.cpp +++ b/externals/grill/xsample/source/inter.cpp @@ -1,11 +1,9 @@ /* - xsample - extended sample objects for Max/MSP and pd (pure data) -Copyright (c) 2001-2004 Thomas Grill (xovo@gmx.net) +Copyright (c) 2001-2005 Thomas Grill (gr@grrrr.org) For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file, "license.txt," in this distribution. - */ #include "main.h" @@ -21,80 +19,64 @@ WARRANTIES, see the file, "license.txt," in this distribution. void xinter::setup(t_classid c) { + FLEXT_CADDBANG(c,0,m_start); + FLEXT_CADDMETHOD_(c,0,"start",m_start); + FLEXT_CADDMETHOD_(c,0,"stop",m_stop); + FLEXT_CADDATTR_VAR_E(c,"interp",interp,m_interp); } -I xinter::m_set(I argc,const t_atom *argv) +void xinter::DoUpdate(unsigned int flags) { - I r = xsample::m_set(argc,argv); - if(r) - // buffer parameters have changed, reset pos/min/max - m_reset(); - return r; -} + xsample::DoUpdate(flags); -V xinter::m_start() -{ - m_refresh(); - doplay = true; - s_dsp(); -} + if(flags&xsc_play) { + switch(outchns) { + case 1: SETSIGFUN(zerofun,TMPLFUN(s_play0,-1,1)); break; + case 2: SETSIGFUN(zerofun,TMPLFUN(s_play0,-1,2)); break; + case 4: SETSIGFUN(zerofun,TMPLFUN(s_play0,-1,4)); break; + default: SETSIGFUN(zerofun,TMPLFUN(s_play0,-1,-1)); + } -V xinter::m_stop() -{ - doplay = false; - s_dsp(); + if(doplay && buf.Ok()) { + if(interp == xsi_4p) + switch(buf.Channels()*1000+outchns) { + case 1001: SETSIGFUN(playfun,TMPLFUN(s_play4,1,1)); break; + case 1002: SETSIGFUN(playfun,TMPLFUN(s_play4,1,2)); break; + case 2001: SETSIGFUN(playfun,TMPLFUN(s_play4,2,1)); break; + case 2002: SETSIGFUN(playfun,TMPLFUN(s_play4,2,2)); break; + case 4001: + case 4002: + case 4003: SETSIGFUN(playfun,TMPLFUN(s_play4,4,-1)); break; + case 4004: SETSIGFUN(playfun,TMPLFUN(s_play4,4,4)); break; + default: SETSIGFUN(playfun,TMPLFUN(s_play4,-1,-1)); + } + else if(interp == xsi_lin) + switch(buf.Channels()*1000+outchns) { + case 1001: SETSIGFUN(playfun,TMPLFUN(s_play2,1,1)); break; + case 1002: SETSIGFUN(playfun,TMPLFUN(s_play2,1,2)); break; + case 2001: SETSIGFUN(playfun,TMPLFUN(s_play2,2,1)); break; + case 2002: SETSIGFUN(playfun,TMPLFUN(s_play2,2,2)); break; + case 4001: + case 4002: + case 4003: SETSIGFUN(playfun,TMPLFUN(s_play2,4,-1)); break; + case 4004: SETSIGFUN(playfun,TMPLFUN(s_play2,4,4)); break; + default: SETSIGFUN(playfun,TMPLFUN(s_play2,-1,-1)); + } + else + switch(buf.Channels()*1000+outchns) { + case 1001: SETSIGFUN(playfun,TMPLFUN(s_play1,1,1)); break; + case 1002: SETSIGFUN(playfun,TMPLFUN(s_play1,1,2)); break; + case 2001: SETSIGFUN(playfun,TMPLFUN(s_play1,2,1)); break; + case 2002: SETSIGFUN(playfun,TMPLFUN(s_play1,2,2)); break; + case 4001: + case 4002: + case 4003: SETSIGFUN(playfun,TMPLFUN(s_play1,4,-1)); break; + case 4004: SETSIGFUN(playfun,TMPLFUN(s_play1,4,4)); break; + default: SETSIGFUN(playfun,TMPLFUN(s_play1,-1,-1)); + } + } + else + SETSIGFUN(playfun,TMPLFUN(s_play0,-1,-1)); + } } - -V xinter::s_dsp() -{ - switch(outchns) { - case 1: SETSIGFUN(zerofun,TMPLFUN(s_play0,-1,1)); break; - case 2: SETSIGFUN(zerofun,TMPLFUN(s_play0,-1,2)); break; - case 4: SETSIGFUN(zerofun,TMPLFUN(s_play0,-1,4)); break; - default: SETSIGFUN(zerofun,TMPLFUN(s_play0,-1,-1)); - } - - if(doplay) { - if(interp == xsi_4p) - switch(buf->Channels()*1000+outchns) { - case 1001: SETSIGFUN(playfun,TMPLFUN(s_play4,1,1)); break; - case 1002: SETSIGFUN(playfun,TMPLFUN(s_play4,1,2)); break; - case 2001: SETSIGFUN(playfun,TMPLFUN(s_play4,2,1)); break; - case 2002: SETSIGFUN(playfun,TMPLFUN(s_play4,2,2)); break; - case 4001: - case 4002: - case 4003: SETSIGFUN(playfun,TMPLFUN(s_play4,4,-1)); break; - case 4004: SETSIGFUN(playfun,TMPLFUN(s_play4,4,4)); break; - default: SETSIGFUN(playfun,TMPLFUN(s_play4,-1,-1)); - } - else if(interp == xsi_lin) - switch(buf->Channels()*1000+outchns) { - case 1001: SETSIGFUN(playfun,TMPLFUN(s_play2,1,1)); break; - case 1002: SETSIGFUN(playfun,TMPLFUN(s_play2,1,2)); break; - case 2001: SETSIGFUN(playfun,TMPLFUN(s_play2,2,1)); break; - case 2002: SETSIGFUN(playfun,TMPLFUN(s_play2,2,2)); break; - case 4001: - case 4002: - case 4003: SETSIGFUN(playfun,TMPLFUN(s_play2,4,-1)); break; - case 4004: SETSIGFUN(playfun,TMPLFUN(s_play2,4,4)); break; - default: SETSIGFUN(playfun,TMPLFUN(s_play2,-1,-1)); - } - else - switch(buf->Channels()*1000+outchns) { - case 1001: SETSIGFUN(playfun,TMPLFUN(s_play1,1,1)); break; - case 1002: SETSIGFUN(playfun,TMPLFUN(s_play1,1,2)); break; - case 2001: SETSIGFUN(playfun,TMPLFUN(s_play1,2,1)); break; - case 2002: SETSIGFUN(playfun,TMPLFUN(s_play1,2,2)); break; - case 4001: - case 4002: - case 4003: SETSIGFUN(playfun,TMPLFUN(s_play1,4,-1)); break; - case 4004: SETSIGFUN(playfun,TMPLFUN(s_play1,4,4)); break; - default: SETSIGFUN(playfun,TMPLFUN(s_play1,-1,-1)); - } - } - else - SETSIGFUN(playfun,TMPLFUN(s_play0,-1,-1)); -} - - diff --git a/externals/grill/xsample/source/inter.h b/externals/grill/xsample/source/inter.h index e3bdd5c8..d0ab3994 100755 --- a/externals/grill/xsample/source/inter.h +++ b/externals/grill/xsample/source/inter.h @@ -1,225 +1,420 @@ /* - xsample - extended sample objects for Max/MSP and pd (pure data) -Copyright (c) 2001-2004 Thomas Grill (xovo@gmx.net) +Copyright (c) 2001-2005 Thomas Grill (gr@grrrr.org) For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file, "license.txt," in this distribution. - */ #ifndef __INTER_H #define __INTER_H -TMPLDEF V xinter::st_play0(const S *,const I ,const I ,const I n,const I inchns,const I outchns,S *const *invecs,S *const *outvecs) +TMPLDEF void xinter::st_play0(const t_sample *,const int ,const int ,const int n,const int inchns,const int outchns,t_sample *const *invecs,t_sample *const *outvecs,bool looped) { // stopped/invalid buffer -> output zero - for(I ci = 0; ci < outchns; ++ci) ZeroSamples(outvecs[ci],n); + for(int ci = 0; ci < outchns; ++ci) ZeroSamples(outvecs[ci],n); } -TMPLDEF V xinter::st_play1(const S *bdt,const I smin,const I smax,const I n,const I inchns,const I outchns,S *const *invecs,S *const *outvecs) +TMPLDEF void xinter::st_play1(const t_sample *bdt,const int smin,const int smax,const int n,const int inchns,const int outchns,t_sample *const *invecs,t_sample *const *outvecs,bool looped) { SIGCHNS(BCHNS,inchns,OCHNS,outchns); // position info are frame units - const S *pos = invecs[0]; - S *const *sig = outvecs; - register I si = 0; + const t_sample *pos = invecs[0]; + t_sample *const *sig = outvecs; // no interpolation // ---------------- - - for(I i = 0; i < n; ++i,++si) { - register const I oint = (I)(*(pos++)); - register const S *fp; - - if(oint >= smin) - if(oint < smax) { - // normal - fp = bdt+oint*BCHNS; - } - else { - // position > last sample ... take only last sample - fp = bdt+(smin == smax?smin:smax-1)*BCHNS; - } - else { - // position < 0 ... take only 0th sample - fp = bdt+smin*BCHNS; - } - - for(I ci = 0; ci < OCHNS; ++ci) - sig[ci][si] = fp[ci]; - } - // clear rest of output channels (if buffer has less channels) - for(I ci = OCHNS; ci < outchns; ++ci) ZeroSamples(sig[ci],n); + if(smin == smax) { + // zero loop length -> assume that smin is a valid sample position... + + int ci; + for(ci = 0; ci < OCHNS; ++ci) SetSamples(sig[ci],n,bdt[smin*BCHNS]); + // clear rest of output channels (if buffer has less channels) + for(; ci < outchns; ++ci) ZeroSamples(sig[ci],n); + } + else if(OCHNS == 1) { + t_sample *sig0 = sig[0]; + for(int i = 0; i < n; ++i) { + register long oint = CASTINT<long>(*(pos++)); + + // for xplay oint can be out of bounds -> check + if(oint >= smin) + if(oint < smax) { + // normal + *(sig0++) = bdt[oint*BCHNS]; + } + else { + // position > last sample ... take only last sample + *(sig0++) = bdt[(smax-1)*BCHNS]; + } + else { + // position < 0 ... take only 0th sample + *(sig0++) = bdt[smin*BCHNS]; + } + } + } + else { + for(int i = 0,si = 0; i < n; ++i,++si) { + register long oint = CASTINT<long>(*(pos++)); + register const t_sample *fp; + + // for xplay oint can be out of bounds -> check + if(oint >= smin) + if(oint < smax) { + // normal + fp = bdt+oint*BCHNS; + } + else { + // position > last sample ... take only last sample + fp = bdt+(smax-1)*BCHNS; + } + else { + // position < 0 ... take only 0th sample + fp = bdt+smin*BCHNS; + } + + for(int ci = 0; ci < OCHNS; ++ci) + sig[ci][si] = fp[ci]; + } + + // clear rest of output channels (if buffer has less channels) + for(int ci = OCHNS; ci < outchns; ++ci) ZeroSamples(sig[ci],n); + } } -TMPLDEF V xinter::st_play2(const S *bdt,const I smin,const I smax,const I n,const I inchns,const I outchns,S *const *invecs,S *const *outvecs) +TMPLDEF void xinter::st_play2(const t_sample *bdt,const int smin,const int smax,const int n,const int inchns,const int outchns,t_sample *const *invecs,t_sample *const *outvecs,bool looped) { - const I plen = smax-smin; //curlen; + const int plen = smax-smin; if(plen < 2) { - st_play1 TMPLCALL (bdt,smin,smax,n,inchns,outchns,invecs,outvecs); + st_play1 TMPLCALL (bdt,smin,smax,n,inchns,outchns,invecs,outvecs,looped); return; } SIGCHNS(BCHNS,inchns,OCHNS,outchns); // position info are frame units - const S *pos = invecs[0]; - S *const *sig = outvecs; - register I si = 0; + const t_sample *pos = invecs[0]; + t_sample *const *sig = outvecs; // linear interpolation // -------------------- - const I maxo = smax-1; // last sample in buffer - - for(I i = 0; i < n; ++i,++si) { - const F o = *(pos++); - register const I oint = (I)o; - - if(oint >= smin) - if(oint < maxo) { - // normal interpolation - register const F frac = o-oint; - register const S *const fp0 = bdt+oint*BCHNS; - register const S *const fp1 = fp0+BCHNS; - for(I ci = 0; ci < OCHNS; ++ci) - sig[ci][si] = fp0[ci]+frac*(fp1[ci]-fp0[ci]); - } - else { - // position is past last sample -> take the last sample - register const S *const fp = bdt+maxo*BCHNS; - for(I ci = 0; ci < OCHNS; ++ci) - sig[ci][si] = fp[ci]; - } - else { - // position is before first sample -> take the first sample - register const S *const fp = bdt+smin*BCHNS; - for(I ci = 0; ci < OCHNS; ++ci) - sig[ci][si] = fp[ci]; - } - } + const int maxo = smax-1; // last sample in buffer + + if(OCHNS == 1) { + t_sample *sig0 = sig[0]; + for(int i = 0; i < n; ++i) { + const float o = *(pos++); + register long oint = CASTINT<long>(o); + const float frac = o-oint; + t_sample fp0,fp1; + + if(oint >= smin) + if(oint < maxo) { + // normal interpolation + fp0 = bdt[oint*BCHNS]; + fp1 = bdt[(oint+1)*BCHNS]; + } + else { + // position is past last sample + if(looped) { + oint = smin+(oint-smin)%plen; + fp0 = bdt[oint*BCHNS]; + fp1 = oint >= maxo?bdt[smin]:fp0; + } + else + fp0 = fp1 = bdt[maxo*BCHNS]; + } + else { + // position is before first sample + if(looped) { + oint = smax-(smin-oint)%plen; + fp0 = bdt[oint*BCHNS]; + fp1 = oint >= maxo?bdt[smin]:fp0; + } + else + fp0 = fp1 = bdt[smin*BCHNS]; + } + + *(sig0++) = fp0+frac*(fp1-fp0); + } + } + else { + for(int i = 0,si = 0; i < n; ++i,++si) { + const float o = *(pos++); + register long oint = CASTINT<long>(o); + const t_sample *fp0,*fp1; + const float frac = o-oint; + + if(oint >= smin) + if(oint < maxo) { + // normal interpolation + fp0 = bdt+oint*BCHNS; + fp1 = fp0+BCHNS; + } + else { + // position is past last sample + if(looped) { + oint = smin+(oint-smin)%plen; + fp0 = bdt+oint*BCHNS; + fp1 = oint >= maxo?bdt+smin:fp0; + } + else + fp0 = fp1 = bdt+maxo*BCHNS; + } + else { + // position is before first sample + if(looped) { + oint = smax-(smin-oint)%plen; + fp0 = bdt+oint*BCHNS; + fp1 = oint >= maxo?bdt+smin:fp0; + } + else + fp0 = fp1 = bdt+smin*BCHNS; + } - // clear rest of output channels (if buffer has less channels) - for(I ci = OCHNS; ci < outchns; ++ci) ZeroSamples(sig[ci],n); + for(int ci = 0; ci < OCHNS; ++ci) + sig[ci][si] = fp0[ci]+frac*(fp1[ci]-fp0[ci]); + } + + // clear rest of output channels (if buffer has less channels) + for(int ci = OCHNS; ci < outchns; ++ci) ZeroSamples(sig[ci],n); + } } -TMPLDEF V xinter::st_play4(const S *bdt,const I smin,const I smax,const I n,const I inchns,const I outchns,S *const *invecs,S *const *outvecs) +TMPLDEF void xinter::st_play4(const t_sample *bdt,const int smin,const int smax,const int n,const int inchns,const int outchns,t_sample *const *invecs,t_sample *const *outvecs,bool looped) { - const I plen = smax-smin; //curlen; + const int plen = smax-smin; //curlen; if(plen < 4) { - if(plen < 2) st_play1 TMPLCALL (bdt,smin,smax,n,inchns,outchns,invecs,outvecs); - else st_play2 TMPLCALL (bdt,smin,smax,n,inchns,outchns,invecs,outvecs); + if(plen < 2) st_play1 TMPLCALL (bdt,smin,smax,n,inchns,outchns,invecs,outvecs,looped); + else st_play2 TMPLCALL (bdt,smin,smax,n,inchns,outchns,invecs,outvecs,looped); return; } SIGCHNS(BCHNS,inchns,OCHNS,outchns); // position info are frame units - const S *pos = invecs[0]; - -#ifdef __VEC__ - // prefetch cache - vec_dst(pos,GetPrefetchConstant(1,n>>2,0),0); - const int pf = GetPrefetchConstant(BCHNS,1,16*BCHNS); -#endif - - S *const *sig = outvecs; - register I si = 0; + const t_sample *pos = invecs[0]; + t_sample *const *sig = outvecs; // 4-point interpolation // --------------------- - const I maxo = smax-1; // last sample in play region - const S *maxp = bdt+maxo*BCHNS; // pointer to last sample - - for(I i = 0; i < n; ++i,++si) { - F o = *(pos++); - register I oint = (I)o; - register F frac; - register const S *fa,*fb,*fc,*fd; - - if(oint > smin) - if(oint < maxo-2) { - // normal case - - fa = bdt+oint*BCHNS-BCHNS; - frac = o-oint; - fb = fa+BCHNS; - #ifdef __VEC__ - vec_dst(fa,pf,0); - #endif - fc = fb+BCHNS; - fd = fc+BCHNS; - } - else { - // after the end - - if(oint > maxo) oint = maxo,o = (float)smax; - frac = o-oint; - - fb = bdt+oint*BCHNS; - fa = fb-BCHNS; - - // \TODO what about wraparound (in loop/palindrome mode) ? - fc = fb >= maxp?maxp:fb+BCHNS; - fd = fc >= maxp?maxp:fc+BCHNS; - } - else { - // before the beginning - - // if oint < first sample set it to first sample - // \TODO what about wraparound (in loop/palindrome mode) ? - if(oint < smin) oint = smin,o = (float)smin; - - // position is first sample - fa = bdt+smin*BCHNS; - - fb = bdt+oint*BCHNS; - frac = o-oint; - fc = fb+BCHNS; - fd = fc+BCHNS; - } - - register F f1 = 0.5f*(frac-1.0f); - register F f3 = frac*3.0f-1.0f; - - for(I ci = 0; ci < OCHNS; ++ci) { - const F amdf = (fa[ci]-fd[ci])*frac; - const F cmb = fc[ci]-fb[ci]; - const F bma = fb[ci]-fa[ci]; - sig[ci][si] = fb[ci] + frac*( cmb - f1 * ( amdf+bma+cmb*f3 ) ); - } - } - -#ifdef __VEC__ - vec_dss(0); -#endif + const int maxo = smax-1; // last sample in play region + + if(OCHNS == 1) { + t_sample *sig0 = sig[0]; + for(int i = 0; i < n; ++i) { + float o = *(pos++); + register long oint = CASTINT<long>(o); + register t_sample fa,fb,fc,fd; + const float frac = o-oint; + register const t_sample *ptr = bdt+oint*BCHNS; + + if(oint > smin) { + if(oint < maxo-2) { + // normal case + fa = ptr[-BCHNS]; + fb = ptr[0]; + fc = ptr[BCHNS]; + fd = ptr[BCHNS*2]; + } + else { + // not enough space at the end + + if(looped) { + // normalize position + oint = smin+(oint-smin)%plen; + goto looped1; + } + else { + // last sample is outside in any case + fd = bdt[maxo*BCHNS]; + + if(oint-1 >= maxo) + // if first is outside, all are outside + fa = fb = fc = fd; + else { + fa = ptr[-BCHNS]; + if(oint >= maxo) + fb = fc = fd; + else { + fb = ptr[0]; + fc = oint+1 < maxo?ptr[BCHNS]:fd; + } + } + } + } + } + else { + // not enough space at the beginning + + if(looped) { + // normalize position + oint = smax-(smin-oint)%plen; +looped1: + ptr = bdt+oint*BCHNS; + + // inside in any case + fb = ptr[0]; + + if(oint < maxo-1) { + fa = oint > smin?ptr[-BCHNS]:bdt[maxo*BCHNS]; + fc = ptr[BCHNS]; + fd = ptr[BCHNS*2]; + } + else { + fa = ptr[-BCHNS]; + fc = oint < maxo?ptr[BCHNS]:ptr[(1-plen)*BCHNS]; + fd = ptr[(2-plen)*BCHNS]; + } + } + else { + // first sample is outside in any case + fa = bdt[smin*BCHNS]; + + if(oint+2 < smin) + // if last is outside, all are outside + fb = fc = fd = fa; + else { + fd = ptr[BCHNS*2]; + if(oint+1 < smin) + fb = fc = fa; + else { + fc = ptr[BCHNS]; + fb = oint < smin?fa:ptr[0]; + } + } + } + } + + const float f1 = 0.5f*(frac-1.0f); + const float f3 = frac*3.0f-1.0f; + + const float amdf = (fa-fd)*frac; + const float cmb = fc-fb; + const float bma = fb-fa; + *(sig0++) = fb + frac*( cmb - f1 * ( amdf+bma+cmb*f3 ) ); + } + } + else { + for(int i = 0,si = 0; i < n; ++i,++si) { + float o = *(pos++); + register long oint = CASTINT<long>(o); + const float frac = o-oint; + register const t_sample *ptr = bdt+oint*BCHNS; + register const t_sample *fa,*fb,*fc,*fd; + + if(oint > smin) + if(oint < maxo-2) { + // normal case + fb = ptr; + fa = fb-BCHNS; + fc = fb+BCHNS; + fd = fc+BCHNS; + } + else { + // not enough space at the end + + if(looped) { + // normalize position + oint = smin+(oint-smin)%plen; + goto looped2; + } + else { + // last sample is outside in any case + fd = bdt+maxo*BCHNS; + + if(oint-1 >= maxo) + // if first is outside, all are outside + fa = fb = fc = fd; + else { + fa = ptr-BCHNS; + if(oint >= maxo) + fb = fc = fd; + else { + fb = ptr; + fc = oint+1 < maxo?ptr+BCHNS:fd; + } + } + } + } + else { + // not enough space at the beginning + + if(looped) { + // normalize position + oint = smax-(smin-oint)%plen; +looped2: + // inside in any case + fb = bdt+oint*BCHNS; + + if(oint < maxo-1) { + fa = oint > smin?fb-BCHNS:bdt+maxo*BCHNS; + fc = fb+BCHNS; + fd = fc+BCHNS; + } + else { + fa = fb-BCHNS; + fc = oint < maxo?fb+BCHNS:bdt+(oint-plen+1)*BCHNS; + fd = bdt+(oint-plen+2)*BCHNS; + } + } + else { + // first sample is outside in any case + fa = bdt+smin*BCHNS; + + if(oint+2 < smin) + // if last is outside, all are outside + fb = fc = fd = fa; + else { + fd = ptr+BCHNS*2; + if(oint+1 < smin) + fb = fc = fa; + else { + fc = ptr+BCHNS; + fb = oint < smin?fa:ptr; + } + } + } + } + + const float f1 = 0.5f*(frac-1.0f); + const float f3 = frac*3.0f-1.0f; + + for(int ci = 0; ci < OCHNS; ++ci) { + const float amdf = (fa[ci]-fd[ci])*frac; + const float cmb = fc[ci]-fb[ci]; + const float bma = fb[ci]-fa[ci]; + sig[ci][si] = fb[ci] + frac*( cmb - f1 * ( amdf+bma+cmb*f3 ) ); + } + } - // clear rest of output channels (if buffer has less channels) - for(I ci = OCHNS; ci < outchns; ++ci) ZeroSamples(sig[ci],n); + // clear rest of output channels (if buffer has less channels) + for(int ci = OCHNS; ci < outchns; ++ci) ZeroSamples(sig[ci],n); + } } -TMPLDEF inline V xinter::s_play0(I n,S *const *invecs,S *const *outvecs) +TMPLDEF inline void xinter::s_play0(int n,t_sample *const *invecs,t_sample *const *outvecs) { - st_play0 TMPLCALL (buf->Data(),curmin,curmax,n,buf->Channels(),outchns,invecs,outvecs); + st_play0 TMPLCALL (buf.Data(),curmin,curmax,n,buf.Channels(),outchns,invecs,outvecs,loopmode == xsl_loop); } -TMPLDEF inline V xinter::s_play1(I n,S *const *invecs,S *const *outvecs) +TMPLDEF inline void xinter::s_play1(int n,t_sample *const *invecs,t_sample *const *outvecs) { - st_play1 TMPLCALL (buf->Data(),curmin,curmax,n,buf->Channels(),outchns,invecs,outvecs); + st_play1 TMPLCALL (buf.Data(),curmin,curmax,n,buf.Channels(),outchns,invecs,outvecs,loopmode == xsl_loop); } -TMPLDEF inline V xinter::s_play2(I n,S *const *invecs,S *const *outvecs) +TMPLDEF inline void xinter::s_play2(int n,t_sample *const *invecs,t_sample *const *outvecs) { - st_play2 TMPLCALL (buf->Data(),curmin,curmax,n,buf->Channels(),outchns,invecs,outvecs); + st_play2 TMPLCALL (buf.Data(),curmin,curmax,n,buf.Channels(),outchns,invecs,outvecs,loopmode == xsl_loop); } -TMPLDEF inline V xinter::s_play4(I n,S *const *invecs,S *const *outvecs) +TMPLDEF inline void xinter::s_play4(int n,t_sample *const *invecs,t_sample *const *outvecs) { - st_play4 TMPLCALL (buf->Data(),curmin,curmax,n,buf->Channels(),outchns,invecs,outvecs); + st_play4 TMPLCALL (buf.Data(),curmin,curmax,n,buf.Channels(),outchns,invecs,outvecs,loopmode == xsl_loop); } #endif diff --git a/externals/grill/xsample/source/main.cpp b/externals/grill/xsample/source/main.cpp index 3cec1b66..030c2675 100644 --- a/externals/grill/xsample/source/main.cpp +++ b/externals/grill/xsample/source/main.cpp @@ -1,26 +1,25 @@ /* - xsample - extended sample objects for Max/MSP and pd (pure data) -Copyright (c) 2001-2004 Thomas Grill (xovo@gmx.net) +Copyright (c) 2001-2005 Thomas Grill (gr@grrrr.org) For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file, "license.txt," in this distribution. - */ #include "main.h" // Initialization function for xsample library -static V xsample_main() +static void xsample_main() { flext::post("-------------------------------"); flext::post("xsample objects, version " XSAMPLE_VERSION); flext::post(""); flext::post(" xrecord~, xplay~, xgroove~ "); - flext::post(" (C)2001-2004 Thomas Grill "); + flext::post(" (C)2001-2005 Thomas Grill "); #ifdef FLEXT_DEBUG - flext::post(" DEBUG BUILD "); + flext::post(""); + flext::post("DEBUG BUILD - " __DATE__ " " __TIME__); #endif flext::post("-------------------------------"); @@ -37,10 +36,6 @@ FLEXT_LIB_SETUP(xsample,xsample_main) void xsample::setup(t_classid c) { - FLEXT_CADDBANG(c,0,m_start); - FLEXT_CADDMETHOD_(c,0,"start",m_start); - FLEXT_CADDMETHOD_(c,0,"stop",m_stop); - FLEXT_CADDMETHOD_(c,0,"set",m_set); FLEXT_CADDMETHOD_(c,0,"print",m_print); FLEXT_CADDMETHOD_(c,0,"refresh",m_refresh); @@ -53,163 +48,160 @@ void xsample::setup(t_classid c) } xsample::xsample(): - buf(NULL), + update(xsc_all), #if FLEXT_SYS == FLEXT_SYS_MAX unitmode(xsu_ms), // Max/MSP defaults to milliseconds #else unitmode(xsu_sample), // PD defaults to samples #endif sclmode(xss_unitsinbuf), - curmin(0),curmax(1<<31) + curmin(0),curmax(1<<(sizeof(curmax)*8-2)) {} -xsample::~xsample() +xsample::~xsample() {} + +bool xsample::Finalize() { -// m_enable(false); // switch off DSP + if(!flext_dsp::Finalize()) return false; - if(buf) delete buf; + // flags have been set in constructor + Refresh(); + return true; } - -BL xsample::bufchk() -{ - if(buf->Valid()) { - if(buf->Update()) { -// post("%s - buffer updated",thisName()); - m_refresh(); - } - return true; - } - else - return false; +int xsample::ChkBuffer(bool refresh) +{ + if(!buf.Ok()) return 0; + + if(buf.Update()) { +#ifdef FLEXT_DEBUG + post("%s - buffer update!",thisName()); +#endif + Update(xsc_buffer); + if(refresh) { + Refresh(); + return buf.Ok() && buf.Valid()?1:0; + } + else + return buf.Valid()?1:0; + } + else + return buf.Valid()?-1:0; } -I xsample::m_set(I argc,const t_atom *argv) +/* called after all buffer objects have been created in the patch */ +void xsample::m_loadbang() { - const t_symbol *sym = argc >= 1?GetASymbol(argv[0]):NULL; - int r = buf->Set(sym); - if(sym && r < 0) post("%s - can't find buffer %s",thisName(),GetString(sym)); - return r; + ChkBuffer(true); } -BL xsample::m_refresh() +void xsample::m_set(int argc,const t_atom *argv) { - BL ret; - if(buf->Set()) { s_dsp(); ret = true; } // channel count may have changed - else ret = false; - - m_units(); - m_sclmode(); - // realize positions... 2 times bufchk()!! - m_min((F)curmin*s2u); // also checks pos - m_max((F)curmax*s2u); // also checks pos - - return ret; + const t_symbol *sym = argc >= 1?GetASymbol(argv[0]):NULL; + int r = buf.Set(sym); + if(sym && r < 0) + post("%s - can't find buffer %s",thisName(),GetString(sym)); + Update(xsc_buffer,true); } -BL xsample::m_reset() +void xsample::m_min(float mn) { - BL ret; - if(buf->Set()) { s_dsp(); ret = true; } // channel count may have changed - else ret = false; - - // now... 4 times bufchk()!! \todo get rid of that - m_units(); - m_sclmode(); - m_min(0); - m_max(buf->Frames()*s2u); + int ret = ChkBuffer(true); - return ret; -} + if(ret && s2u) { + long cmn = CASTINT<long>(mn/s2u+0.5f); // conversion to samples -V xsample::m_loadbang() -{ - m_reset(); -} + if(cmn < 0) + curmin = 0; + else if(cmn > curmax) + curmin = curmax; + else + curmin = cmn; -V xsample::m_units(xs_unit mode) -{ - if(mode != xsu__) unitmode = mode; - - switch(unitmode) { - case xsu_sample: // samples - s2u = 1; - break; - case xsu_buffer: // buffer size - s2u = bufchk()?1.f/buf->Frames():0; - break; - case xsu_ms: // ms - s2u = 1000.f/Samplerate(); - break; - case xsu_s: // s - s2u = 1.f/Samplerate(); - break; - default: - post("%s: Unknown unit mode",thisName()); + Update(xsc_range,true); } } -V xsample::m_sclmode(xs_sclmd mode) +void xsample::m_max(float mx) { - if(mode != xss__) sclmode = mode; - - switch(sclmode) { - case 0: // samples/units - sclmin = 0; sclmul = s2u; - break; - case 1: // samples/units from recmin to recmax - sclmin = curmin; sclmul = s2u; - break; - case 2: // unity between 0 and buffer size - sclmin = 0; sclmul = (bufchk() && buf->Frames())?1.f/buf->Frames():0; - break; - case 3: // unity between recmin and recmax - sclmin = curmin; sclmul = curmin != curmax?1.f/(curmax-curmin):0; - break; - default: - post("%s: Unknown scale mode",thisName()); - } -} + int ret = ChkBuffer(true); -V xsample::m_min(F mn) -{ -// if(!bufchk()) return; // if invalid do nothing (actually, it should be delayed) + if(ret && s2u) { + long cmx = CASTINT<long>(mx/s2u+0.5f); // conversion to samples - if(s2u) { - mn /= s2u; // conversion to samples - if(mn < 0) mn = 0; - else if(mn > curmax) mn = (F)curmax; - curmin = (I)(mn+.5); + if(cmx > buf.Frames()) + curmax = buf.Frames(); + else if(cmx < curmin) + curmax = curmin; + else + curmax = cmx; - m_sclmode(); + Update(xsc_range,true); } } -V xsample::m_max(F mx) +void xsample::m_dsp(int /*n*/,t_sample *const * /*insigs*/,t_sample *const * /*outsigs*/) { -// if(!bufchk()) return; // if invalid do nothing (actually, it should be delayed) + // this is hopefully called at change of sample rate ?! - if(s2u) { - mx /= s2u; // conversion to samples - if(mx > buf->Frames()) mx = (F)buf->Frames(); - else if(mx < curmin) mx = (F)curmin; - curmax = (I)(mx+.5); +#ifdef FLEXT_DEBUG + post("%s - DSP reset!",thisName()); +#endif - m_sclmode(); - } + // for PD at least this is also called if a table has been deleted... + // then we must reset the buffer + + Update(xsc_srate|xsc_buffer,true); } -V xsample::m_all() +void xsample::DoReset() { - if(!bufchk()) return; // if invalid do nothing (actually, it should be delayed) - - curmin = 0; curmax = buf->Frames(); - m_sclmode(); + ResetRange(); } -V xsample::m_dsp(I /*n*/,S *const * /*insigs*/,S *const * /*outsigs*/) +void xsample::DoUpdate(unsigned int flags) { - // this is hopefully called at change of sample rate ?! - - if(!m_refresh()) s_dsp(); + if(flags&xsc_buffer) + buf.Set(); + + if(flags&xsc_range && buf.Ok()) { + if(curmin < 0) curmin = 0; + if(curmax > buf.Frames()) curmax = buf.Frames(); + } + + if(flags&xsc_units) { + switch(unitmode) { + case xsu_sample: // samples + s2u = 1; + break; + case xsu_buffer: // buffer size + s2u = buf.Ok() && buf.Frames()?1.f/buf.Frames():0; + break; + case xsu_ms: // ms + s2u = 1000.f/Samplerate(); + break; + case xsu_s: // s + s2u = 1.f/Samplerate(); + break; + default: + post("%s - Unknown unit mode",thisName()); + } + + switch(sclmode) { + case xss_unitsinbuf: // samples/units + sclmin = 0; sclmul = s2u; + break; + case xss_unitsinloop: // samples/units from recmin to recmax + sclmin = curmin; sclmul = s2u; + break; + case xss_buffer: // unity between 0 and buffer size + sclmin = 0; sclmul = buf.Ok() && buf.Frames()?1.f/buf.Frames():0; + break; + case xss_loop: // unity between recmin and recmax + sclmin = curmin; sclmul = curmin < curmax?1.f/(curmax-curmin):0; + break; + default: + post("%s - Unknown scale mode",thisName()); + } + } } diff --git a/externals/grill/xsample/source/main.h b/externals/grill/xsample/source/main.h index 3608a55c..97e4516d 100644 --- a/externals/grill/xsample/source/main.h +++ b/externals/grill/xsample/source/main.h @@ -1,11 +1,9 @@ /* - xsample - extended sample objects for Max/MSP and pd (pure data) -Copyright (c) 2001-2004 Thomas Grill (xovo@gmx.net) +Copyright (c) 2001-2005 Thomas Grill (gr@grrrr.org) For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file, "license.txt," in this distribution. - */ #ifndef __XSAMPLE_H @@ -13,18 +11,19 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include "prefix.h" -#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 406) -#error You need at least flext version 0.4.6 +#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 500) +#error You need at least flext version 0.5.0 #endif -#define XSAMPLE_VERSION "0.3.1pre3" +#define XSAMPLE_VERSION "0.3.1pre4" // most compilers are somehow broken - in other words - can't handle all C++ features #if defined(_MSC_VER) // MS VC 6.0 can't handle <int,int> templates?! -> no optimization - #if _MSC_VER >= 1300 +// MS VC .NET 2002 just dies with template optimization switched on + #if _MSC_VER >= 1310 #define TMPLOPT #endif #elif defined(__BORLANDC__) @@ -51,17 +50,6 @@ WARRANTIES, see the file, "license.txt," in this distribution. #endif -// lazy me -#define F float -#define D double -#define I int -#define L long -#define C char -#define V void -#define BL bool -#define S t_sample - - #if defined(__MWERKS__) && !defined(__MACH__) #define STD std #else @@ -92,6 +80,32 @@ WARRANTIES, see the file, "license.txt," in this distribution. } #endif +#if FLEXT_CPU == FLEXT_CPU_INTEL && defined(__GNUC__) +template<typename I,typename F> inline I CASTINT(F o) { return lrintf(o); } +#elif FLEXT_CPU == FLEXT_CPU_INTEL && defined(_MSC_VER) +template<typename I,typename F> +inline I CASTINT(F x) { +// by Laurent de Soras (http://ldesoras.free.fr) +// assert (x > static_cast <double> (INT_MIN / 2) + 1.0); +// assert (x < static_cast <double> (INT_MAX / 2) + 1.0); + const float round_towards_m_i = -0.5f; + I i; + __asm + { + fld x + fadd st,st + fabs + fadd round_towards_m_i + fistp i + sar i, 1 + } + if(x < 0) i = -i; + return i; +} +#else +template<typename I,typename F> inline I CASTINT(F o) { return static_cast<I>(o); } +#endif + class xsample: public flext_dsp @@ -101,73 +115,133 @@ class xsample: public: xsample(); ~xsample(); + + enum xs_change { + xsc__ = 0, + xsc_units = 0x0001, + xsc_play = 0x0002, + xsc_pos = 0x0008, + xsc_range = 0x0010, + xsc_transport = 0x0020, + xsc_fade = 0x0040, + + xsc_intp = xsc_play, + xsc_srate = xsc_play|xsc_units, + xsc_chns = xsc_play, + xsc_loop = xsc_play, + xsc_startstop = xsc_play|xsc_transport, + xsc_buffer = xsc_units|xsc_pos|xsc_range|xsc_play, + xsc_reset = xsc_buffer, + xsc_all = 0xffff + }; - enum xs_unit { - xsu__ = -1, // don't change - xsu_sample = 0,xsu_buffer,xsu_ms,xsu_s - }; + enum xs_unit { + xsu_sample = 0,xsu_buffer,xsu_ms,xsu_s + }; enum xs_intp { - xsi__ = -1, // don't change xsi_none = 0,xsi_4p,xsi_lin }; enum xs_sclmd { - xss__ = -1, // don't change xss_unitsinbuf = 0,xss_unitsinloop,xss_buffer,xss_loop }; protected: - buffer *buf; - - virtual V m_start() = 0; - virtual V m_stop() = 0; - virtual BL m_reset(); - - virtual I m_set(I argc,const t_atom *argv); - virtual V m_print() = 0; - virtual BL m_refresh(); - virtual V m_loadbang(); - - virtual V m_units(xs_unit u = xsu__); - virtual V m_sclmode(xs_sclmd u = xss__); - - virtual V m_all(); - virtual V m_min(F mn); - virtual V m_max(F mx); - - virtual V m_dsp(I n,S *const *insigs,S *const *outsigs); - virtual V s_dsp() = 0; - - xs_unit unitmode; //iunitmode,ounitmode; - xs_sclmd sclmode; //isclmode,osclmode; - - L curmin,curmax; //,curlen; // in samples - I sclmin; // in samples - F sclmul; - F s2u; // sample to unit conversion factor - - inline F scale(F smp) const { return (smp-sclmin)*sclmul; } + virtual bool Finalize(); + + buffer buf; + + void m_reset() + { + ChkBuffer(true); + DoReset(); + Refresh(); + } + + void m_set(int argc,const t_atom *argv); + + void m_refresh() + { + Update(xsc_buffer,true); + } + + void m_units(xs_unit mode) + { + unitmode = mode; + Update(xsc_units,true); + } + + void m_sclmode(xs_sclmd mode) + { + sclmode = mode; + Update(xsc_units,true); + } + + void m_all() + { + ChkBuffer(true); + ResetRange(); + Refresh(); + } + + void m_min(float mn); + void m_max(float mx); + + xs_unit unitmode; + xs_sclmd sclmode; + + long curmin,curmax; //,curlen; // in samples + long sclmin; // in samples + float sclmul; + float s2u; // sample to unit conversion factor + + inline float scale(float smp) const { return (smp-sclmin)*sclmul; } - static V arrscale(I n,const S *in,S *out,S add,S mul) { flext::ScaleSamples(out,in,mul,add,n); } - inline V arrscale(I n,const S *in,S *out) const { arrscale(n,in,out,-sclmin*sclmul,sclmul); } + static void arrscale(int n,const t_sample *in,t_sample *out,t_sample add,t_sample mul) { flext::ScaleSamples(out,in,mul,add,n); } + inline void arrscale(int n,const t_sample *in,t_sample *out) const { arrscale(n,in,out,-sclmin*sclmul,sclmul); } - static V arrmul(I n,const S *in,S *out,S mul) { flext::MulSamples(out,in,mul,n); } - inline V arrmul(I n,const S *in,S *out) const { arrmul(n,in,out,(S)(1./s2u)); } - - BL bufchk(); - - V mg_buffer(AtomList &l) { if(buf && buf->Symbol()) { l(1); SetSymbol(l[0],buf->Symbol()); } else l(); } - inline V ms_buffer(const AtomList &l) { m_set(l.Count(),l.Atoms()); } - - inline V mg_min(F &v) const { v = curmin*s2u; } - inline V mg_max(F &v) const { v = curmax*s2u; } + static void arrmul(int n,const t_sample *in,t_sample *out,t_sample mul) { flext::MulSamples(out,in,mul,n); } + inline void arrmul(int n,const t_sample *in,t_sample *out) const { arrmul(n,in,out,(t_sample)(1.f/s2u)); } + + void mg_buffer(AtomList &l) { if(buf.Symbol()) { l(1); SetSymbol(l[0],buf.Symbol()); } } + inline void ms_buffer(const AtomList &l) { m_set(l.Count(),l.Atoms()); } + + inline void mg_min(float &v) const { v = curmin*s2u; } + inline void mg_max(float &v) const { v = curmax*s2u; } + + void Refresh() { if(update && !Initing()) { DoUpdate(update); update = xsc__; } } + void Update(unsigned int f,bool refr = false) { update |= f; if(refr) Refresh(); } + + //! return 0...invalid, 1...changed, -1...unchanged + int ChkBuffer(bool refr = false); + + typedef flext::buffer::lock_t lock_t; + + //! Lock buffer (buffer must be checked ok) + lock_t Lock() { return buf.Lock(); } + //! Unlock buffer (buffer must be checked ok) + void Unlock(lock_t l) { buf.Unlock(l); } + + void ResetRange() + { + curmin = 0; + curmax = buf.Frames(); + Update(xsc_range); + } + + virtual void DoReset(); + virtual void DoUpdate(unsigned int flags); + + virtual void m_loadbang(); + virtual void m_print() = 0; + virtual void m_dsp(int n,t_sample *const *insigs,t_sample *const *outsigs); private: - static V setup(t_classid c); - FLEXT_CALLBACK(m_start) - FLEXT_CALLBACK(m_stop) + unsigned int update; + + static void setup(t_classid c); FLEXT_CALLBACK_V(m_set) FLEXT_CALLBACK(m_print) @@ -206,25 +280,25 @@ protected: #endif #define DEFSIGFUN(NAME) \ - static V st_##NAME(thisType *obj,I n,S *const *in,S *const *out) { obj->NAME (n,in,out); } \ - V NAME(I n,S *const *in,S *const *out) + static void st_##NAME(thisType *obj,int n,t_sample *const *in,t_sample *const *out) { obj->NAME (n,in,out); } \ + void NAME(int n,t_sample *const *in,t_sample *const *out) #define TMPLSIGFUN(NAME) \ - TMPLDEF static V st_##NAME(thisType *obj,I n,S *const *in,S *const *out) { obj->NAME TMPLCALL (n,in,out); } \ - TMPLDEF V NAME(I n,S *const *in,S *const *out) + TMPLDEF static void st_##NAME(thisType *obj,int n,t_sample *const *in,t_sample *const *out) { obj->NAME TMPLCALL (n,in,out); } \ + TMPLDEF void NAME(int n,t_sample *const *in,t_sample *const *out) - #define TMPLSTFUN(NAME) TMPLDEF static V NAME(const S *bdt,const I smin,const I smax,const I n,const I inchns,const I outchns,S *const *invecs,S *const *outvecs) + #define TMPLSTFUN(NAME) TMPLDEF static void NAME(const t_sample *bdt,const int smin,const int smax,const int n,const int inchns,const int outchns,t_sample *const *invecs,t_sample *const *outvecs) #define SETSIGFUN(VAR,FUN) v_##VAR = FUN #define SETSTFUN(VAR,FUN) VAR = FUN #define DEFSIGCALL(NAME) \ - inline V NAME(I n,S *const *in,S *const *out) { (*v_##NAME)(this,n,in,out); } \ - V (*v_##NAME)(thisType *obj,I n,S *const *in,S *const *out) + inline void NAME(int n,t_sample *const *in,t_sample *const *out) { (*v_##NAME)(this,n,in,out); } \ + void (*v_##NAME)(thisType *obj,int n,t_sample *const *in,t_sample *const *out) #define DEFSTCALL(NAME) \ - V (*NAME)(const S *bdt,const I smin,const I smax,const I n,const I inchns,const I outchns,S *const *invecs,S *const *outvecs) + void (*NAME)(const t_sample *bdt,const int smin,const int smax,const int n,const int inchns,const int outchns,t_sample *const *invecs,t_sample *const *outvecs) #else #ifdef TMPLOPT @@ -241,20 +315,20 @@ protected: #define TMPLSTF(FUN,BCHNS,IOCHNS) TMPLFUN(FUN,BCHNS,IOCHNS) - #define DEFSIGFUN(NAME) V NAME(I n,S *const *in,S *const *out) - #define TMPLSIGFUN(NAME) TMPLDEF V NAME(I n,S *const *in,S *const *out) - #define TMPLSTFUN(NAME) TMPLDEF static V NAME(const S *bdt,const I smin,const I smax,const I n,const I inchns,const I outchns,S *const *invecs,S *const *outvecs) + #define DEFSIGFUN(NAME) void NAME(int n,t_sample *const *in,t_sample *const *out) + #define TMPLSIGFUN(NAME) TMPLDEF void NAME(int n,t_sample *const *in,t_sample *const *out) + #define TMPLSTFUN(NAME) TMPLDEF static void NAME(const t_sample *bdt,const int smin,const int smax,const int n,const int inchns,const int outchns,t_sample *const *invecs,t_sample *const *outvecs,bool looped) #define SETSIGFUN(VAR,FUN) v_##VAR = FUN #define DEFSIGCALL(NAME) \ - inline V NAME(I n,S *const *in,S *const *out) { (this->*v_##NAME)(n,in,out); } \ - V (thisType::*v_##NAME)(I n,S *const *invecs,S *const *outvecs) + inline void NAME(int n,t_sample *const *in,t_sample *const *out) { (this->*v_##NAME)(n,in,out); } \ + void (thisType::*v_##NAME)(int n,t_sample *const *invecs,t_sample *const *outvecs) #define SETSTFUN(VAR,FUN) VAR = FUN #define DEFSTCALL(NAME) \ - V (*NAME)(const S *bdt,const I smin,const I smax,const I n,const I inchns,const I outchns,S *const *invecs,S *const *outvecs) + void (*NAME)(const t_sample *bdt,const int smin,const int smax,const int n,const int inchns,const int outchns,t_sample *const *invecs,t_sample *const *outvecs,bool looped) #endif @@ -269,18 +343,18 @@ protected: #ifdef TMPLOPT // optimization by using constants for channel numbers #define SIGCHNS(BCHNS,bchns,IOCHNS,iochns) \ - const I BCHNS = _BCHNS_ < 0?(bchns):_BCHNS_; \ - const I IOCHNS = _IOCHNS_ < 0?MIN(iochns,BCHNS):MIN(_IOCHNS_,BCHNS) + const int BCHNS = _BCHNS_ < 0?(bchns):_BCHNS_; \ + const int IOCHNS = _IOCHNS_ < 0?MIN(iochns,BCHNS):MIN(_IOCHNS_,BCHNS) #else // no template optimization #if FLEXT_SYS == FLEXT_SYS_PD // only mono buffers #define SIGCHNS(BCHNS,bchns,IOCHNS,iochns) \ - const I BCHNS = 1; \ - const I IOCHNS = MIN(iochns,BCHNS) + const int BCHNS = 1; \ + const int IOCHNS = MIN(iochns,BCHNS) #else // MAXMSP #define SIGCHNS(BCHNS,bchns,IOCHNS,iochns) \ - const I BCHNS = bchns; \ - const I IOCHNS = MIN(iochns,BCHNS) + const int BCHNS = bchns; \ + const int IOCHNS = MIN(iochns,BCHNS) #endif #endif @@ -291,19 +365,42 @@ class xinter: FLEXT_HEADER_S(xinter,xsample,setup) public: - xinter(): outchns(1),doplay(false),interp(xsi_4p) {} - -protected: - virtual I m_set(I argc,const t_atom *argv); - virtual V m_start(); - virtual V m_stop(); + enum xs_loop { + xsl_once = 0,xsl_loop,xsl_bidir + }; + + xinter() + : outchns(1),doplay(false) + , interp(xsi_4p),loopmode(xsl_loop) + {} + + void m_start() + { + ChkBuffer(); + doplay = true; + Update(xsc_startstop,true); + } + + void m_stop() + { + ChkBuffer(); + doplay = false; + Update(xsc_startstop,true); + } + + void m_interp(xs_intp mode) + { + interp = mode; + Update(xsc_intp,true); + } - inline V m_interp(xs_intp mode = xsi__) { interp = mode; s_dsp(); } +protected: - I outchns; - BL doplay; + int outchns; + bool doplay; xs_intp interp; + xs_loop loopmode; TMPLSIGFUN(s_play0); TMPLSIGFUN(s_play1); @@ -318,13 +415,18 @@ protected: DEFSIGCALL(playfun); DEFSIGCALL(zerofun); - virtual V s_dsp(); + virtual void DoUpdate(unsigned int flags); -private: - static V setup(t_classid c); + FLEXT_CALLBACK(m_start) + FLEXT_CALLBACK(m_stop) FLEXT_CALLSET_E(m_interp,xs_intp) FLEXT_ATTRGET_E(interp,xs_intp) + + FLEXT_ATTRGET_E(loopmode,xs_loop) + +private: + static void setup(t_classid c); }; #ifdef TMPLOPT @@ -332,5 +434,3 @@ private: #endif #endif - - diff --git a/externals/grill/xsample/source/play.cpp b/externals/grill/xsample/source/play.cpp index d5c9fb94..268b853a 100644 --- a/externals/grill/xsample/source/play.cpp +++ b/externals/grill/xsample/source/play.cpp @@ -1,11 +1,9 @@ /* - xsample - extended sample objects for Max/MSP and pd (pure data) -Copyright (c) 2001-2004 Thomas Grill (xovo@gmx.net) +Copyright (c) 2001-2005 Thomas Grill (gr@grrrr.org) For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file, "license.txt," in this distribution. - */ #include "main.h" @@ -22,29 +20,40 @@ class xplay: FLEXT_HEADER_S(xplay,xinter,setup) public: - xplay(I argc,const t_atom *argv); + xplay(int argc,const t_atom *argv); + + void m_loop(xs_loop lp) + { + loopmode = lp; + Update(xsc_loop,true); + } - virtual BL Init(); - - virtual V m_help(); - virtual V m_print(); +protected: + virtual void m_help(); + virtual void m_print(); + virtual void m_signal(int n,t_sample *const *in,t_sample *const *out); private: - static V setup(t_classid c); + static void setup(t_classid c); - virtual V m_signal(I n,S *const *in,S *const *out); + FLEXT_CALLSET_E(m_loop,xs_loop) }; FLEXT_LIB_DSP_V("xplay~",xplay) -V xplay::setup(t_classid c) +void xplay::setup(t_classid c) { DefineHelp(c,"xplay~"); + + FLEXT_CADDATTR_VAR_E(c,"loop",loopmode,m_loop); } -xplay::xplay(I argc,const t_atom *argv) +xplay::xplay(int argc,const t_atom *argv) { - I argi = 0; + // set the loopmode to non-wrapping (for sample interpolation) + loopmode = xsl_once; + + int argi = 0; #if FLEXT_SYS == FLEXT_SYS_MAX if(argc > argi && CanbeInt(argv[argi])) { outchns = GetAInt(argv[argi]); @@ -53,7 +62,7 @@ xplay::xplay(I argc,const t_atom *argv) #endif if(argc > argi && IsSymbol(argv[argi])) { - buf = new buffer(GetSymbol(argv[argi]),true); + buf.Set(GetSymbol(argv[argi]),true); argi++; #if FLEXT_SYS == FLEXT_SYS_MAX @@ -65,37 +74,31 @@ xplay::xplay(I argc,const t_atom *argv) } #endif } - else - buf = new buffer(NULL,true); - AddInSignal("Messages and Signal of playing position"); // pos signal - for(I ci = 0; ci < outchns; ++ci) { - C tmp[30]; + AddInSignal("Messages and Signal of playing position"); // pos signal + for(int ci = 0; ci < outchns; ++ci) { + char tmp[30]; STD::sprintf(tmp,"Audio signal channel %i",ci+1); AddOutSignal(tmp); } - - m_reset(); } -BL xplay::Init() -{ - if(xinter::Init()) { - m_reset(); - return true; - } - else - return false; -} - -V xplay::m_signal(I n,S *const *in,S *const *out) +void xplay::m_signal(int n,t_sample *const *in,t_sample *const *out) { + int ret = ChkBuffer(true); + // check whether buffer is invalid or changed - if(bufchk()) { + if(ret) { + const lock_t l = Lock(); + // convert position units to frames arrmul(n,in[0],out[0]); // call resample routine playfun(n,out,out); + + Unlock(l); + + Refresh(); } else zerofun(n,out,out); @@ -103,13 +106,13 @@ V xplay::m_signal(I n,S *const *in,S *const *out) -V xplay::m_help() +void xplay::m_help() { post("%s - part of xsample objects, version " XSAMPLE_VERSION,thisName()); #ifdef FLEXT_DEBUG post("compiled on " __DATE__ " " __TIME__); #endif - post("(C) Thomas Grill, 2001-2004"); + post("(C) Thomas Grill, 2001-2005"); #if FLEXT_SYS == FLEXT_SYS_MAX post("Arguments: %s [channels=1] [buffer]",thisName()); #else @@ -120,7 +123,7 @@ V xplay::m_help() post("Methods:"); post("\thelp: shows this help"); post("\tset name: set buffer"); - post("\tenable 0/1: turn dsp calculation off/on"); + post("\tenable 0/1: turn dsp calculation off/on"); post("\tprint: print current settings"); post("\tbang/start: begin playing"); post("\tstop: stop playing"); @@ -128,17 +131,16 @@ V xplay::m_help() post("\trefresh: checks buffer and refreshes outlets"); post("\t@units 0/1/2/3: set units to samples/buffer size/ms/s"); post("\t@interp 0/1/2: set interpolation to off/4-point/linear"); + post("\t@loop 0/1/2: sets looping (interpolation) to off/forward/bidirectional"); post(""); } -V xplay::m_print() +void xplay::m_print() { - const C *interp_txt[] = {"off","4-point","linear"}; + const char *interp_txt[] = {"off","4-point","linear"}; // print all current settings post("%s - current settings:",thisName()); - post("bufname = '%s', length = %.3f, channels = %i",buf->Name(),(F)(buf->Frames()*s2u),buf->Channels()); - post("out channels = %i, samples/unit = %.3f, interpolation = %s",outchns,(F)(1./s2u),interp_txt[interp >= xsi_none && interp <= xsi_lin?interp:xsi_none]); + post("bufname = '%s', length = %.3f, channels = %i",buf.Name(),(float)(buf.Frames()*s2u),buf.Channels()); + post("out channels = %i, samples/unit = %.3f, interpolation = %s",outchns,(float)(1./s2u),interp_txt[interp >= xsi_none && interp <= xsi_lin?interp:xsi_none]); post(""); } - - diff --git a/externals/grill/xsample/source/prefix.h b/externals/grill/xsample/source/prefix.h index ef9cb7ea..415f07c3 100644 --- a/externals/grill/xsample/source/prefix.h +++ b/externals/grill/xsample/source/prefix.h @@ -12,3 +12,4 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include <flext.h> +#include <math.h> diff --git a/externals/grill/xsample/source/record.cpp b/externals/grill/xsample/source/record.cpp index a30f87cb..1df51c81 100644 --- a/externals/grill/xsample/source/record.cpp +++ b/externals/grill/xsample/source/record.cpp @@ -1,11 +1,9 @@ /* - xsample - extended sample objects for Max/MSP and pd (pure data) -Copyright (c) 2001-2004 Thomas Grill (xovo@gmx.net) +Copyright (c) 2001-2005 Thomas Grill (gr@grrrr.org) For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file, "license.txt," in this distribution. - */ #include "main.h" @@ -22,53 +20,54 @@ class xrecord: FLEXT_HEADER_S(xrecord,xsample,setup) public: - xrecord(I argc,const t_atom *argv); - - virtual BL Init(); - - virtual V m_help(); - virtual V m_print(); + xrecord(int argc,const t_atom *argv); - virtual I m_set(I argc,const t_atom *argv); - - virtual V m_pos(F pos); - virtual V m_all(); - virtual V m_start(); - virtual V m_stop(); + void m_pos(float pos) + { + curpos = pos?CASTINT<long>(pos/s2u+.5):0; + Update(xsc_pos); + Refresh(); + } - virtual BL m_reset(); + inline void mg_pos(float &v) const { v = curpos*s2u; } - virtual V m_units(xs_unit md = xsu__); - virtual V m_min(F mn); - virtual V m_max(F mx); + void m_start(); + void m_stop(); - inline V m_append(BL app) { if(!(appmode = app)) m_pos(0); } + inline void m_append(bool app) + { + appmode = app; + Update(xsc_play); + if(!appmode) m_pos(0); + } - virtual V m_draw(I argc,const t_atom *argv); + void m_draw(int argc,const t_atom *argv); protected: - I inchns; - BL sigmode,appmode; - F drintv; - - BL dorec,doloop; - I mixmode; - L curpos; // in samples + int inchns; + bool sigmode,appmode; + float drintv; - inline V outputmin() { ToOutFloat(1,curmin*s2u); } - inline V outputmax() { ToOutFloat(2,curmax*s2u); } + bool dorec,doloop; + int mixmode; + long curpos; // in samples - inline V mg_pos(F &v) const { v = curpos*s2u; } + virtual void DoReset(); + virtual void DoUpdate(unsigned int flags); + + virtual void m_help(); + virtual void m_print(); + virtual void m_signal(int n,t_sample *const *in,t_sample *const *out); private: - static V setup(t_classid c); - - virtual V s_dsp(); + static void setup(t_classid c); TMPLSIGFUN(s_rec); DEFSIGCALL(recfun); - virtual V m_signal(I n,S *const *in,S *const *out); + + FLEXT_CALLBACK(m_start) + FLEXT_CALLBACK(m_stop) FLEXT_CALLVAR_F(mg_pos,m_pos) FLEXT_CALLBACK(m_all) @@ -90,10 +89,14 @@ private: FLEXT_LIB_DSP_V("xrecord~",xrecord) -V xrecord::setup(t_classid c) +void xrecord::setup(t_classid c) { DefineHelp(c,"xrecord~"); + FLEXT_CADDBANG(c,0,m_start); + FLEXT_CADDMETHOD_(c,0,"start",m_start); + FLEXT_CADDMETHOD_(c,0,"stop",m_stop); + FLEXT_CADDATTR_VAR(c,"pos",mg_pos,m_pos); FLEXT_CADDATTR_VAR(c,"min",mg_min,m_min); FLEXT_CADDATTR_VAR(c,"max",mg_max,m_max); @@ -107,14 +110,14 @@ V xrecord::setup(t_classid c) FLEXT_CADDATTR_VAR(c,"append",appmode,m_append); } -xrecord::xrecord(I argc,const t_atom *argv): +xrecord::xrecord(int argc,const t_atom *argv): inchns(1), sigmode(false),appmode(true), drintv(0), dorec(false),doloop(false), mixmode(0) { - I argi = 0; + int argi = 0; #if FLEXT_SYS == FLEXT_SYS_MAX if(argc > argi && CanbeInt(argv[argi])) { inchns = GetAInt(argv[argi]); @@ -123,7 +126,7 @@ xrecord::xrecord(I argc,const t_atom *argv): #endif if(argc > argi && IsSymbol(argv[argi])) { - buf = new buffer(GetSymbol(argv[argi]),true); + buf.Set(GetSymbol(argv[argi]),true); argi++; #if FLEXT_SYS == FLEXT_SYS_MAX @@ -135,11 +138,9 @@ xrecord::xrecord(I argc,const t_atom *argv): } #endif } - else - buf = new buffer(NULL,true); - for(I ci = 0; ci < inchns; ++ci) { - C tmp[40]; + for(int ci = 0; ci < inchns; ++ci) { + char tmp[40]; STD::sprintf(tmp,ci == 0?"Messages/audio channel %i":"Audio channel %i",ci+1); AddInSignal(tmp); // audio signals } @@ -155,127 +156,69 @@ xrecord::xrecord(I argc,const t_atom *argv): FLEXT_ADDMETHOD(inchns+2,m_max); } +void xrecord::m_start() +{ + ChkBuffer(); -BL xrecord::Init() -{ - if(xsample::Init()) { - m_reset(); - return true; - } - else - return false; -} - -V xrecord::m_units(xs_unit mode) -{ - xsample::m_units(mode); - - m_sclmode(); - outputmin(); - outputmax(); -} - -V xrecord::m_min(F mn) -{ - xsample::m_min(mn); - m_pos(curpos*s2u); - outputmin(); -} - -V xrecord::m_max(F mx) -{ - xsample::m_max(mx); - m_pos(curpos*s2u); - outputmax(); -} - -V xrecord::m_all() -{ - xsample::m_all(); - outputmin(); - outputmax(); -} - -V xrecord::m_pos(F pos) -{ - curpos = pos?(L)(pos/s2u+.5):0; - - if(curpos < curmin) curpos = curmin; - else if(curpos > curmax) curpos = curmax; -} - - -I xrecord::m_set(I argc,const t_atom *argv) -{ - I r = xsample::m_set(argc,argv); - if(r) - // buffer parameters have changed, reset pos/min/max - m_reset(); - return r; -} + if(!sigmode && !appmode) { curpos = 0; Update(xsc_pos); } -V xrecord::m_start() -{ - if(!sigmode && !appmode) m_pos(0); - m_refresh(); - dorec = true; - buf->SetRefrIntv(drintv); - s_dsp(); + dorec = true; + Update(xsc_startstop); + Refresh(); } -V xrecord::m_stop() +void xrecord::m_stop() { - dorec = false; - buf->Dirty(true); - buf->SetRefrIntv(0); - s_dsp(); + ChkBuffer(); + dorec = false; + Update(xsc_startstop); + Refresh(); } -BL xrecord::m_reset() +void xrecord::DoReset() { + xsample::DoReset(); curpos = 0; - return xsample::m_reset(); } -V xrecord::m_draw(I argc,const t_atom *argv) +void xrecord::m_draw(int argc,const t_atom *argv) { if(argc >= 1) { - drintv = GetInt(argv[0]); - if(dorec) buf->SetRefrIntv(drintv); + drintv = GetAInt(argv[0]); + if(dorec) buf.SetRefrIntv(drintv); } else - buf->Dirty(true); + buf.Dirty(true); } - -TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) +TMPLDEF void xrecord::s_rec(int n,t_sample *const *invecs,t_sample *const *outvecs) { - SIGCHNS(BCHNS,buf->Channels(),ICHNS,inchns); + SIGCHNS(BCHNS,buf.Channels(),ICHNS,inchns); - const S *const *sig = invecs; - register I si = 0; - const S *on = invecs[inchns]; - S *pos = outvecs[0]; + const t_sample *const *sig = invecs; + register int si = 0; + const t_sample *on = invecs[inchns]; + t_sample *pos = outvecs[0]; - BL lpbang = false; - register const F pf = sclmul; - register L o = curpos; + bool lpbang = false; + register const float pf = sclmul; + register long o = curpos; if(o < curmin) o = curmin; -// if(buf && dorec && curlen > 0) { - if(buf && dorec && curmax > curmin) { + if(dorec && curmax > curmin) { while(n) { - L ncur = curmax-o; // at max to buffer or recording end + long ncur = curmax-o; // at max to buffer or recording end if(ncur <= 0) { // end of buffer if(doloop) { - o = curmin; -// ncur = curlen; - ncur = curmax-o; + ncur = curmax-(o = curmin); } - else - m_stop(); // loop expired; + else { + // loop expired; + dorec = false; + Update(xsc_startstop); + } lpbang = true; } @@ -284,9 +227,9 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) if(ncur > n) ncur = n; - register I i; - register S *bf = buf->Data()+o*BCHNS; - register F p = scale(o); + register int i; + register t_sample *bf = buf.Data()+o*BCHNS; + register float p = scale(o); if(sigmode) { if(appmode) { @@ -295,7 +238,7 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) switch(mixmode) { case 0: for(i = 0; i < ncur; ++i,++si) { - if(*(on++) >= 0) { + if(!(*(on++) < 0)) { for(int ci = 0; ci < ICHNS; ++ci) bf[ci] = sig[ci][si]; bf += BCHNS; @@ -307,8 +250,8 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) break; case 1: for(i = 0; i < ncur; ++i,++si) { - register const S g = *(on++); - if(g >= 0) { + register const t_sample g = *(on++); + if(!(g < 0)) { for(int ci = 0; ci < ICHNS; ++ci) bf[ci] = bf[ci]*(1.-g)+sig[ci][si]*g; bf += BCHNS; @@ -320,7 +263,7 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) break; case 2: for(i = 0; i < ncur; ++i,++si) { - if(*(on++) >= 0) { + if(!(*(on++) < 0)) { for(int ci = 0; ci < ICHNS; ++ci) bf[ci] += sig[ci][si]; bf += BCHNS; @@ -337,7 +280,7 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) switch(mixmode) { case 0: { for(i = 0; i < ncur; ++i,++si) { - if(*(on++) >= 0) + if(!(*(on++) < 0)) { for(int ci = 0; ci < ICHNS; ++ci) bf[ci] = sig[ci][si]; @@ -346,15 +289,15 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) } else { *(pos++) = p = scale(o = 0); - bf = buf->Data(); + bf = buf.Data(); } } break; } case 1: { for(i = 0; i < ncur; ++i,++si) { - register const S g = *(on++); - if(g >= 0) { + register const t_sample g = *(on++); + if(!(g < 0)) { for(int ci = 0; ci < ICHNS; ++ci) bf[ci] = bf[ci]*(1.-g)+sig[ci][si]*g; bf += BCHNS; @@ -362,14 +305,14 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) } else { *(pos++) = p = scale(o = 0); - bf = buf->Data(); + bf = buf.Data(); } } break; } case 2: { for(i = 0; i < ncur; ++i,++si) { - if(*(on++) >= 0) + if(!(*(on++) < 0)) { for(int ci = 0; ci < ICHNS; ++ci) bf[ci] += sig[ci][si]; @@ -378,7 +321,7 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) } else { *(pos++) = p = scale(o = 0); - bf = buf->Data(); + bf = buf.Data(); } } break; @@ -393,8 +336,8 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) switch(mixmode) { case 0: { for(int ci = 0; ci < ICHNS; ++ci) { - register S *b = bf+ci; - register const F *s = sig[ci]+si; + register t_sample *b = bf+ci; + register const float *s = sig[ci]+si; for(i = 0; i < ncur; ++i,b += BCHNS,++s) *b = *s; } @@ -403,7 +346,7 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) } case 1: { for(i = 0; i < ncur; ++i,++si) { - register const S w = *(on++); + register const t_sample w = *(on++); for(int ci = 0; ci < ICHNS; ++ci) bf[ci] = bf[ci]*(1.-w)+sig[ci][si]*w; bf += BCHNS; @@ -412,9 +355,10 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) } case 2: { for(int ci = 0; ci < ICHNS; ++ci) { - register S *b = bf+ci; - register const F *s = sig[ci]+si; - for(i = 0; i < ncur; ++i,b += BCHNS,++s) *b += *s; + register t_sample *b = bf+ci; + register const float *s = sig[ci]+si; + for(i = 0; i < ncur; ++i,b += BCHNS,++s) + *b += *s; } si += ncur; break; @@ -430,52 +374,81 @@ TMPLDEF V xrecord::s_rec(I n,S *const *invecs,S *const *outvecs) } curpos = o; - buf->Dirty(); + buf.Dirty(); } if(n) { - register F p = scale(o); + register float p = scale(o); while(n--) *(pos++) = p; } if(lpbang) ToOutBang(3); } -V xrecord::m_signal(I n,S *const *in,S *const *out) +void xrecord::m_signal(int n,t_sample *const *in,t_sample *const *out) { - if(bufchk()) + int ret = ChkBuffer(true); + + if(ret) { // call the appropriate dsp function - recfun(n,in,out); + + const lock_t l = Lock(); + recfun(n,in,out); + Unlock(l); + + Refresh(); + } else // set position signal to zero ZeroSamples(out[0],n); } -V xrecord::s_dsp() +void xrecord::DoUpdate(unsigned int flags) { - switch(buf->Channels()*1000+inchns) { - case 1001: SETSIGFUN(recfun,TMPLFUN(s_rec,1,1)); break; - case 1002: SETSIGFUN(recfun,TMPLFUN(s_rec,1,2)); break; - case 2001: SETSIGFUN(recfun,TMPLFUN(s_rec,2,1)); break; - case 2002: SETSIGFUN(recfun,TMPLFUN(s_rec,2,2)); break; - case 4001: - case 4002: - case 4003: SETSIGFUN(recfun,TMPLFUN(s_rec,4,-1)); break; - case 4004: SETSIGFUN(recfun,TMPLFUN(s_rec,4,4)); break; - default: SETSIGFUN(recfun,TMPLFUN(s_rec,-1,-1)); break; - } + xsample::DoUpdate(flags); + + if(flags&(xsc_pos|xsc_range)) { + if(curpos < curmin) curpos = curmin; + else if(curpos > curmax) curpos = curmax; + } + + if(flags&xsc_range) { + ToOutFloat(1,curmin*s2u); + ToOutFloat(2,curmax*s2u); + } + + if(flags&xsc_transport && buf.Ok()) { + if(dorec) + buf.SetRefrIntv(drintv); + else { + buf.Dirty(true); + buf.SetRefrIntv(0); + } + } + + if(flags&xsc_play) { + switch(buf.Channels()*1000+inchns) { + case 1001: SETSIGFUN(recfun,TMPLFUN(s_rec,1,1)); break; + case 1002: SETSIGFUN(recfun,TMPLFUN(s_rec,1,2)); break; + case 2001: SETSIGFUN(recfun,TMPLFUN(s_rec,2,1)); break; + case 2002: SETSIGFUN(recfun,TMPLFUN(s_rec,2,2)); break; + case 4001: + case 4002: + case 4003: SETSIGFUN(recfun,TMPLFUN(s_rec,4,-1)); break; + case 4004: SETSIGFUN(recfun,TMPLFUN(s_rec,4,4)); break; + default: SETSIGFUN(recfun,TMPLFUN(s_rec,-1,-1)); break; + } + } } - - -V xrecord::m_help() +void xrecord::m_help() { post("%s - part of xsample objects, version " XSAMPLE_VERSION,thisName()); #ifdef FLEXT_DEBUG post("compiled on " __DATE__ " " __TIME__); #endif - post("(C) Thomas Grill, 2001-2004"); + post("(C) Thomas Grill, 2001-2005"); #if FLEXT_SYS == FLEXT_SYS_MAX post("Arguments: %s [channels=1] [buffer]",thisName()); #else @@ -506,15 +479,14 @@ V xrecord::m_help() post(""); } -V xrecord::m_print() +void xrecord::m_print() { - static const C sclmode_txt[][20] = {"units","units in loop","buffer","loop"}; + static const char sclmode_txt[][20] = {"units","units in loop","buffer","loop"}; // print all current settings post("%s - current settings:",thisName()); - post("bufname = '%s', length = %.3f, channels = %i",buf->Name(),(F)(buf->Frames()*s2u),buf->Channels()); - post("in channels = %i, frames/unit = %.3f, scale mode = %s",inchns,(F)(1./s2u),sclmode_txt[sclmode]); + post("bufname = '%s', length = %.3f, channels = %i",buf.Name(),(float)(buf.Frames()*s2u),buf.Channels()); + post("in channels = %i, frames/unit = %.3f, scale mode = %s",inchns,(float)(1./s2u),sclmode_txt[sclmode]); post("sigmode = %s, append = %s, loop = %s, mixmode = %i",sigmode?"yes":"no",appmode?"yes":"no",doloop?"yes":"no",mixmode); post(""); } - |