aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/xsample/source
diff options
context:
space:
mode:
Diffstat (limited to 'externals/grill/xsample/source')
-rw-r--r--externals/grill/xsample/source/groove.cpp788
-rw-r--r--externals/grill/xsample/source/inter.cpp128
-rwxr-xr-xexternals/grill/xsample/source/inter.h511
-rw-r--r--externals/grill/xsample/source/main.cpp244
-rw-r--r--externals/grill/xsample/source/main.h306
-rw-r--r--externals/grill/xsample/source/play.cpp86
-rw-r--r--externals/grill/xsample/source/prefix.h1
-rw-r--r--externals/grill/xsample/source/record.cpp336
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("");
}
-