aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/xsample/source/groove.cpp
diff options
context:
space:
mode:
authorThomas Grill <xovo@users.sourceforge.net>2005-01-08 04:59:44 +0000
committerThomas Grill <xovo@users.sourceforge.net>2005-01-08 04:59:44 +0000
commiteba585829684fcf54a0c8614709d2c10c75032b4 (patch)
tree9f4e2ca184f37852fd5c5d8e30df10b100f25ffd /externals/grill/xsample/source/groove.cpp
parent0709ac9fabf4184675df1c3d8e205a2790adaadb (diff)
merge in branch "20041229-unify"
- some small cleanups os x fixes minor updates improved buffer handling simplify updates Mac adaptations - made xcode project preparing xsample 0.3.0 release updated for build system some optimizations - fixed loop record bug Completion of attribute functionality, revisited and updated help files svn path=/trunk/; revision=2477
Diffstat (limited to 'externals/grill/xsample/source/groove.cpp')
-rw-r--r--externals/grill/xsample/source/groove.cpp788
1 files changed, 313 insertions, 475 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("");
}
-