cwAudioTransforms.h/cpp : Implemented wt_osc,wt_seq_osc,multi_ch_wt_seq_osc.
This commit is contained in:
parent
1b4ad4f45f
commit
dfd1805ba1
@ -59,7 +59,7 @@ namespace cw
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc_t test( const cw::object_t* args )
|
||||
rc_t test()
|
||||
{
|
||||
double hann_15[] = { 0.0, 0.04951557, 0.1882551 , 0.38873953, 0.61126047, 0.8117449, 0.95048443, 1.0, 0.95048443, 0.8117449, 0.61126047, 0.38873953, 0.1882551, 0.04951557, 0.0 };
|
||||
double hann_16[] = { 0.0, 0.04322727, 0.1654347 , 0.3454915 , 0.55226423, 0.75, 0.9045085 , 0.9890738, 0.9890738, 0.9045085, 0.75, 0.55226423, 0.3454915, 0.1654347 , 0.04322727, 0.0 };
|
||||
@ -87,7 +87,7 @@ namespace cw
|
||||
|
||||
namespace ola
|
||||
{
|
||||
rc_t test( const cw::object_t* args )
|
||||
rc_t test()
|
||||
{
|
||||
typedef float sample_t;
|
||||
|
||||
@ -150,7 +150,7 @@ namespace cw
|
||||
|
||||
namespace shift_buf
|
||||
{
|
||||
rc_t test( const object_t* args )
|
||||
rc_t test()
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
typedef float sample_t;
|
||||
@ -223,7 +223,7 @@ namespace cw
|
||||
|
||||
namespace pv_anl
|
||||
{
|
||||
rc_t test( const object_t* args )
|
||||
rc_t test()
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
pv_anl::fobj_t* pva = nullptr;
|
||||
@ -253,12 +253,256 @@ namespace cw
|
||||
|
||||
}
|
||||
|
||||
rc_t test( const cw::object_t* args )
|
||||
namespace wt_osc
|
||||
{
|
||||
wnd_func::test(args);
|
||||
ola::test(args);
|
||||
shift_buf::test(args);
|
||||
return kOkRC;
|
||||
typedef float sample_t;
|
||||
typedef float srate_t;
|
||||
|
||||
rc_t test()
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
srate_t srate = 8;
|
||||
sample_t aV[] = { 7,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0 };
|
||||
|
||||
struct wt_str<sample_t,srate_t> wt{
|
||||
.tid = kLoopWtTId,
|
||||
.cyc_per_loop = 0,
|
||||
.aV = aV,
|
||||
.aN = 16,
|
||||
.rms = 0,
|
||||
.hz = 1,
|
||||
.srate = srate,
|
||||
.pad_smpN = 1,
|
||||
.posn_smp_idx = 0
|
||||
};
|
||||
|
||||
struct obj_str<sample_t,srate_t> obj;
|
||||
init(&obj,&wt);
|
||||
|
||||
unsigned yN = (int)(srate*2);
|
||||
sample_t yV[yN];
|
||||
unsigned actual = 0;
|
||||
process(&obj, yV, yN,actual);
|
||||
|
||||
vop::print( yV, yN, "%f");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace wt_seq_osc
|
||||
{
|
||||
typedef float sample_t;
|
||||
typedef float srate_t;
|
||||
|
||||
rc_t test()
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
srate_t srate = 8;
|
||||
sample_t aV[] = { 7,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0 };
|
||||
|
||||
struct wt_osc::wt_str<sample_t,srate_t> wt{
|
||||
.tid = wt_osc::kOneShotWtTId,
|
||||
.cyc_per_loop = 0,
|
||||
.aV = aV,
|
||||
.aN = 16,
|
||||
.rms = 0,
|
||||
.hz = 1,
|
||||
.srate = srate,
|
||||
.pad_smpN = 1,
|
||||
.posn_smp_idx = 0
|
||||
};
|
||||
|
||||
struct wt_osc::wt_str<sample_t,srate_t> wt0 = wt;
|
||||
struct wt_osc::wt_str<sample_t,srate_t> wt1 = wt;
|
||||
struct wt_osc::wt_str<sample_t,srate_t> wt2 = wt;
|
||||
|
||||
|
||||
wt1.tid = wt_osc::kLoopWtTId;
|
||||
wt1.posn_smp_idx = 16;
|
||||
wt2.tid = wt_osc::kLoopWtTId;
|
||||
wt2.posn_smp_idx = 32;
|
||||
|
||||
struct wt_osc::wt_str<sample_t,srate_t> wtA[] = {
|
||||
wt0,
|
||||
wt1,
|
||||
wt2
|
||||
};
|
||||
|
||||
struct wt_seq_osc::wt_seq_str<sample_t,srate_t> wt_seq{
|
||||
.wtA = wtA,
|
||||
.wtN = 3
|
||||
};
|
||||
|
||||
struct wt_seq_osc::obj_str<sample_t,srate_t> obj;
|
||||
init(&obj,&wt_seq);
|
||||
|
||||
unsigned yN = (int)(srate*10);
|
||||
sample_t yV[yN];
|
||||
unsigned actual = 0;
|
||||
unsigned yi = 0;
|
||||
unsigned yDspSmpCnt = 8;
|
||||
while( yi < yN && is_init(&obj) )
|
||||
{
|
||||
unsigned frmSmpN = std::min(yN-yi,yDspSmpCnt);
|
||||
process(&obj, yV+yi, frmSmpN, actual);
|
||||
assert( actual == frmSmpN );
|
||||
yi += actual;
|
||||
}
|
||||
|
||||
vop::print( yV, yi, "%5.3f",nullptr,8);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace multi_ch_wt_seq_osc
|
||||
{
|
||||
typedef float sample_t;
|
||||
typedef float srate_t;
|
||||
|
||||
rc_t test()
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
unsigned chN = 2;
|
||||
srate_t srate = 8;
|
||||
sample_t a0V[] = { 7,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0 };
|
||||
sample_t a1V[] = { 17,10,11,12,13,14,15,16,17,10,11,12,13,14,15,16,17,10 };
|
||||
sample_t a2V[] = { 27,20,21,22,23,24,25,26,27,20,21,22,23,24,25,26,27,20 };
|
||||
|
||||
struct wt_osc::wt_str<sample_t,srate_t> wt{
|
||||
.tid = wt_osc::kOneShotWtTId,
|
||||
.cyc_per_loop = 0,
|
||||
.aV = a0V,
|
||||
.aN = 16,
|
||||
.rms = 0,
|
||||
.hz = 1,
|
||||
.srate = srate,
|
||||
.pad_smpN = 1,
|
||||
.posn_smp_idx = 0
|
||||
};
|
||||
|
||||
struct wt_osc::wt_str<sample_t,srate_t> wt0 = wt;
|
||||
struct wt_osc::wt_str<sample_t,srate_t> wt1 = wt;
|
||||
struct wt_osc::wt_str<sample_t,srate_t> wt2 = wt;
|
||||
|
||||
|
||||
wt1.tid = wt_osc::kLoopWtTId;
|
||||
wt1.posn_smp_idx = 16;
|
||||
wt1.aV = a1V;
|
||||
|
||||
wt2.tid = wt_osc::kLoopWtTId;
|
||||
wt2.posn_smp_idx = 32;
|
||||
wt2.aV = a2V;
|
||||
|
||||
struct wt_osc::wt_str<sample_t,srate_t> wtA[] = {
|
||||
wt0,
|
||||
wt1,
|
||||
wt2
|
||||
};
|
||||
|
||||
struct wt_seq_osc::wt_seq_str<sample_t,srate_t> wt_seq{
|
||||
.wtA = wtA,
|
||||
.wtN = 3
|
||||
};
|
||||
|
||||
|
||||
struct wt_seq_osc::wt_seq_str<sample_t,srate_t> chA[] = {
|
||||
wt_seq,
|
||||
wt_seq
|
||||
};
|
||||
|
||||
struct multi_ch_wt_seq_str<sample_t,srate_t> mcs = {
|
||||
.chA = chA,
|
||||
.chN = chN
|
||||
};
|
||||
|
||||
|
||||
struct obj_str<sample_t,srate_t> obj;
|
||||
|
||||
if((rc = create(&obj,chN)) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
if((rc = setup(&obj,&mcs)) != kOkRC )
|
||||
goto errLabel;
|
||||
else
|
||||
{
|
||||
unsigned yN = (int)(srate*10);
|
||||
unsigned actual = 0;
|
||||
unsigned yi = 0;
|
||||
unsigned yDspSmpCnt = 8;
|
||||
|
||||
|
||||
while( yi < yN && !is_done(&obj) )
|
||||
{
|
||||
unsigned frmSmpN = std::min(yN-yi,yDspSmpCnt);
|
||||
sample_t yV[frmSmpN*chN];
|
||||
|
||||
if((rc = process(&obj, yV, chN, frmSmpN, actual)) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
assert( actual == frmSmpN );
|
||||
|
||||
vop::print( yV, frmSmpN*chN, "%5.3f",nullptr,8);
|
||||
|
||||
yi += actual;
|
||||
}
|
||||
}
|
||||
|
||||
errLabel:
|
||||
destroy(&obj);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
rc_t test( const test::test_args_t& args )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
|
||||
if( textIsEqual(args.test_label,"wnd_func") )
|
||||
{
|
||||
rc = wnd_func::test();
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( textIsEqual(args.test_label,"ola") )
|
||||
{
|
||||
rc = ola::test();
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( textIsEqual(args.test_label,"shift_buf") )
|
||||
{
|
||||
rc = shift_buf::test();
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( textIsEqual(args.test_label,"wt_osc") )
|
||||
{
|
||||
rc = wt_osc::test();
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( textIsEqual(args.test_label,"wt_seq_osc") )
|
||||
{
|
||||
rc = wt_seq_osc::test();
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( textIsEqual(args.test_label,"multi_ch_wt_seq_osc") )
|
||||
{
|
||||
rc = multi_ch_wt_seq_osc::test();
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
rc = cwLogError(kInvalidArgRC,"Unknown test case module:%s test:%s.",args.module_label,args.test_label);
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -779,9 +779,9 @@ namespace cw
|
||||
|
||||
ifft::exec_polar( p->ft, magV, phsV );
|
||||
|
||||
// convert double to float
|
||||
T0 v[ p->ft->outN ];
|
||||
vop::copy( v, p->ft->outV, p->ft->outN );
|
||||
// convert double to float
|
||||
T0 v[ p->ft->outN ];
|
||||
vop::copy( v, p->ft->outV, p->ft->outN );
|
||||
|
||||
ola::exec( p->ola, v, p->ft->outN );
|
||||
|
||||
@ -1234,7 +1234,446 @@ namespace cw
|
||||
}
|
||||
|
||||
|
||||
rc_t test( const cw::object_t* args );
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
// wt_osc
|
||||
//
|
||||
|
||||
namespace wt_osc
|
||||
{
|
||||
|
||||
typedef enum {
|
||||
kInvalidWtTId,
|
||||
kOneShotWtTId,
|
||||
kLoopWtTId
|
||||
} wt_tid_t;
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
struct wt_str
|
||||
{
|
||||
wt_tid_t tid;
|
||||
unsigned cyc_per_loop; // count of cycles in the loop
|
||||
sample_t* aV; // aV[ padN + aN + padN ]
|
||||
unsigned aN; // Count of unique samples
|
||||
double rms;
|
||||
double hz;
|
||||
srate_t srate;
|
||||
unsigned pad_smpN;
|
||||
unsigned posn_smp_idx; // The location of this sample in the original audio file.
|
||||
};
|
||||
|
||||
|
||||
template< typename sample_t >
|
||||
sample_t table_read_2( const sample_t* tab, double frac )
|
||||
{
|
||||
|
||||
unsigned i0 = floor(frac);
|
||||
unsigned i1 = i0 + 1;
|
||||
double f = frac - int(frac);
|
||||
|
||||
sample_t r = (sample_t)(tab[i0] + (tab[i1] - tab[i0]) * f);
|
||||
|
||||
//intf("r:%f frac:%f i0:%i f:%f\n",r,frac,i0,f);
|
||||
return r;
|
||||
}
|
||||
|
||||
template< typename sample_t >
|
||||
sample_t hann_read( double x, double N )
|
||||
{
|
||||
while( x > N)
|
||||
x -= N;
|
||||
|
||||
x = x - (N/2) ;
|
||||
|
||||
return (sample_t)(0.5 + 0.5 * cos(2*M_PI * x / N));
|
||||
}
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
struct obj_str
|
||||
{
|
||||
const wt_str<sample_t,srate_t>* wt;
|
||||
|
||||
double phs; // current fractional phase into wt->aV[]
|
||||
double fsmp_per_wt; //
|
||||
|
||||
};
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
bool is_init(const struct obj_str<sample_t,srate_t>* p)
|
||||
{ return p->wt != nullptr; }
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
void init(struct obj_str<sample_t,srate_t>* p, struct wt_str<sample_t,srate_t>* wt)
|
||||
{
|
||||
if( wt == nullptr )
|
||||
p->wt = nullptr;
|
||||
else
|
||||
{
|
||||
double fsmp_per_cyc = wt->srate/wt->hz;
|
||||
p->fsmp_per_wt = fsmp_per_cyc * 2; // each wavetable contains 2
|
||||
|
||||
p->wt = wt;
|
||||
p->phs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
void _process_loop(struct obj_str<sample_t,srate_t>* p, sample_t* aV, unsigned aN, unsigned& actual_Ref)
|
||||
{
|
||||
double phs0 = p->phs;
|
||||
double phs1 = phs0 + p->fsmp_per_wt/2;
|
||||
unsigned smp_per_wt = (int)floor(p->fsmp_per_wt); //
|
||||
|
||||
while(phs1 >= smp_per_wt)
|
||||
phs1 -= smp_per_wt;
|
||||
|
||||
for(unsigned i=0; i<aN; ++i)
|
||||
{
|
||||
sample_t s0 = table_read_2( p->wt->aV+p->wt->pad_smpN, phs0 );
|
||||
sample_t s1 = table_read_2( p->wt->aV+p->wt->pad_smpN, phs1 );
|
||||
|
||||
sample_t e0 = hann_read<sample_t>(phs0,p->fsmp_per_wt);
|
||||
sample_t e1 = hann_read<sample_t>(phs1,p->fsmp_per_wt);
|
||||
|
||||
aV[ i ] = e0*s0 + e1*s1;
|
||||
|
||||
// advance the phases of the oscillators
|
||||
phs0 += 1;
|
||||
while(phs0 >= smp_per_wt)
|
||||
phs0 -= smp_per_wt;
|
||||
|
||||
phs1 += 1;
|
||||
while(phs1 >= smp_per_wt)
|
||||
phs1 -= smp_per_wt;
|
||||
|
||||
}
|
||||
|
||||
p->phs = phs0;
|
||||
actual_Ref = aN;
|
||||
}
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
void _process_one_shot(struct obj_str<sample_t,srate_t>* p, sample_t* aV, unsigned aN, unsigned& actual_Ref)
|
||||
{
|
||||
unsigned phs = (unsigned)p->phs;
|
||||
unsigned i;
|
||||
for(i=0; i<aN && phs<p->wt->aN; ++i,++phs)
|
||||
aV[i] = p->wt->aV[ p->wt->pad_smpN + phs ];
|
||||
|
||||
p->phs = phs;
|
||||
actual_Ref = i;
|
||||
|
||||
}
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
void process(struct obj_str<sample_t,srate_t>* p, sample_t* aV, unsigned aN, unsigned& actual_Ref)
|
||||
{
|
||||
actual_Ref = 0;
|
||||
switch( p->wt->tid )
|
||||
{
|
||||
case wt_osc::kLoopWtTId:
|
||||
_process_loop(p,aV,aN,actual_Ref);
|
||||
break;
|
||||
|
||||
case wt_osc::kOneShotWtTId:
|
||||
_process_one_shot(p,aV,aN,actual_Ref);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rc_t test();
|
||||
|
||||
} // wt_osc
|
||||
|
||||
|
||||
namespace wt_seq_osc
|
||||
{
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
struct wt_seq_str
|
||||
{
|
||||
struct wt_osc::wt_str<sample_t,srate_t>* wtA;
|
||||
unsigned wtN;
|
||||
};
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
struct obj_str
|
||||
{
|
||||
struct wt_seq_osc::wt_seq_str<sample_t,srate_t>* wt_seq;
|
||||
struct wt_osc::obj_str<sample_t,srate_t> osc0;
|
||||
struct wt_osc::obj_str<sample_t,srate_t> osc1;
|
||||
|
||||
unsigned wt_idx; // index of wt0 in wt_seq->wtA[]
|
||||
|
||||
|
||||
unsigned mix_interval_smp; // osc0/osc1 crossfade interval in samples
|
||||
unsigned mix_phs; // current crossfade phase (0 <= mix_phs <= mix_interval_smp)
|
||||
};
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
rc_t _update_wt( struct obj_str<sample_t,srate_t>* p, unsigned wt_idx )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
struct wt_osc::wt_str<sample_t,srate_t>* wt0 = nullptr;
|
||||
struct wt_osc::wt_str<sample_t,srate_t>* wt1 = nullptr;
|
||||
|
||||
p->mix_interval_smp = 0;
|
||||
|
||||
if( wt_idx < p->wt_seq->wtN )
|
||||
wt0 = p->wt_seq->wtA + wt_idx;
|
||||
|
||||
if( (wt_idx+1) < p->wt_seq->wtN )
|
||||
{
|
||||
wt1 = p->wt_seq->wtA + (wt_idx+1);
|
||||
|
||||
unsigned posn0_smp_idx = wt0->posn_smp_idx;
|
||||
unsigned posn1_smp_idx = wt1->posn_smp_idx;
|
||||
|
||||
if( posn1_smp_idx < posn0_smp_idx )
|
||||
{
|
||||
rc = cwLogError(kInvalidStateRC,"The position of the wavetable at wt. seq index:%i must be greater than the position of the previous wt.",wt_idx+1);
|
||||
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
p->mix_interval_smp = posn1_smp_idx - posn0_smp_idx;
|
||||
}
|
||||
|
||||
wt_osc::init(&p->osc0,wt0);
|
||||
wt_osc::init(&p->osc1,wt1);
|
||||
|
||||
p->wt_idx = wt_idx;
|
||||
p->mix_phs = 0;
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
bool is_init( const struct obj_str<sample_t,srate_t>* p )
|
||||
{
|
||||
return is_init(&p->osc0);
|
||||
}
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
rc_t init(struct obj_str<sample_t,srate_t>* p, struct wt_seq_osc::wt_seq_str<sample_t,srate_t>* wt_seq)
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
p->wt_seq = wt_seq;
|
||||
p->wt_idx = 0;
|
||||
|
||||
if((rc = _update_wt(p,0)) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
rc_t process(struct obj_str<sample_t,srate_t>* p, sample_t* aV, unsigned aN, unsigned& actual_Ref)
|
||||
{
|
||||
actual_Ref = 0;
|
||||
|
||||
rc_t rc = kOkRC;
|
||||
unsigned actual;
|
||||
bool atk_fl = p->wt_idx==0 && p->osc0.wt->tid == wt_osc::kOneShotWtTId;
|
||||
|
||||
// if the osc is in the attack phase
|
||||
if( atk_fl )
|
||||
{
|
||||
// update aV[aN] from osc0
|
||||
wt_osc::process(&p->osc0,aV,aN,actual);
|
||||
|
||||
actual_Ref = actual;
|
||||
|
||||
// if all requested samples were generated we are done ...
|
||||
if( actual >= aN )
|
||||
return rc;
|
||||
|
||||
// otherwise all requested samples were not generated
|
||||
// fill the rest of aV[] from the next one or two wave tables.
|
||||
aN -= actual;
|
||||
aV += actual;
|
||||
|
||||
// initialize osc0 and osc1
|
||||
if((rc = _update_wt(p, 1)) != kOkRC )
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
wt_osc::process(&p->osc0,aV,aN,actual);
|
||||
|
||||
// if the second oscillator is initialized
|
||||
if( wt_osc::is_init(&p->osc1) )
|
||||
{
|
||||
unsigned actual1 = 0;
|
||||
sample_t tV[ aN ];
|
||||
// generate aN samples into tV[aN]
|
||||
wt_osc::process(&p->osc1,tV,aN,actual1);
|
||||
|
||||
assert( actual1 == actual );
|
||||
|
||||
|
||||
sample_t g = (sample_t)std::min(1.0,(double)p->mix_phs / p->mix_interval_smp);
|
||||
|
||||
// mix the output of the second oscillator into the output signal
|
||||
vop::scale_add(aV,aV,(1.0f-g),tV,g,actual1);
|
||||
|
||||
p->mix_phs += actual;
|
||||
|
||||
// if the osc0/osc1 xfade is complete ...
|
||||
if( p->mix_phs >= p->mix_interval_smp )
|
||||
{
|
||||
// ... then advance to the next set of wavetables
|
||||
if((rc = _update_wt(p, p->wt_idx+1)) != kOkRC )
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
actual_Ref += actual;
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc_t test();
|
||||
|
||||
} // wt_seq_osc
|
||||
|
||||
namespace multi_ch_wt_seq_osc
|
||||
{
|
||||
template< typename sample_t, typename srate_t >
|
||||
struct multi_ch_wt_seq_str
|
||||
{
|
||||
struct wt_seq_osc::wt_seq_str<sample_t,srate_t>* chA;
|
||||
unsigned chN;
|
||||
};
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
struct obj_str
|
||||
{
|
||||
const struct multi_ch_wt_seq_str<sample_t,srate_t>* mcs = nullptr;
|
||||
struct wt_seq_osc::obj_str<sample_t,srate_t>* chA = nullptr;
|
||||
unsigned chAllocN = 0;
|
||||
unsigned chN = 0;
|
||||
bool done_fl = true;
|
||||
};
|
||||
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
rc_t create(struct obj_str<sample_t,srate_t>* p, unsigned maxChN, const struct multi_ch_wt_seq_str<sample_t,srate_t>* mcs=nullptr )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
|
||||
destroy(p);
|
||||
|
||||
p->chA = mem::allocZ< struct wt_seq_osc::obj_str<sample_t,srate_t> >(maxChN);
|
||||
p->chAllocN = maxChN;
|
||||
p->chN = 0;
|
||||
p->done_fl = true;
|
||||
|
||||
if( mcs != nullptr )
|
||||
setup(p,mcs);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
rc_t destroy(struct obj_str<sample_t,srate_t>* p )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
|
||||
mem::release(p->chA);
|
||||
p->chAllocN = 0;
|
||||
p->chN = 0;
|
||||
p->done_fl = true;
|
||||
return rc;
|
||||
}
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
rc_t setup( struct obj_str<sample_t,srate_t>* p, const struct multi_ch_wt_seq_str<sample_t,srate_t>* mcs )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
|
||||
if( mcs->chN > p->chAllocN )
|
||||
{
|
||||
rc = cwLogError(kInvalidArgRC,"Invalid multi-ch-wt-osc channel count. (%i > %i)",mcs->chN,p->chAllocN);
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
|
||||
p->mcs = mcs;
|
||||
p->done_fl = false;
|
||||
p->chN = mcs->chN;
|
||||
for(unsigned i=0; i<mcs->chN; ++i)
|
||||
if((rc = wt_seq_osc::init(p->chA+i,mcs->chA + i)) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
errLabel:
|
||||
if( rc != kOkRC )
|
||||
rc = cwLogError(rc,"multi-ch-wt-osc setup failed.");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
rc_t is_done( struct obj_str<sample_t,srate_t>* p )
|
||||
{ return p->done_fl; }
|
||||
|
||||
template< typename sample_t, typename srate_t >
|
||||
rc_t process( struct obj_str<sample_t,srate_t>* p, sample_t* aM, unsigned chN, unsigned frmN, unsigned& actual_Ref )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
unsigned actual = 0;
|
||||
unsigned doneN = 0;
|
||||
|
||||
for(unsigned i=0; i<p->chN; ++i)
|
||||
{
|
||||
unsigned actual0 = 0;
|
||||
sample_t* aV = aM + (i*frmN);
|
||||
|
||||
if( !wt_seq_osc::is_init(p->chA + i) )
|
||||
{
|
||||
vop::zero(aV,frmN);
|
||||
actual0 = frmN;
|
||||
doneN += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if((rc = wt_seq_osc::process(p->chA + i, aV, frmN, actual0 )) != kOkRC )
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if( i!=0 && actual0 != actual )
|
||||
{
|
||||
rc = cwLogError(kInvalidStateRC,"An inconsistent sample count was generated across channels (%i != !i).",actual0,actual);
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
actual = actual0;
|
||||
}
|
||||
|
||||
actual_Ref = actual;
|
||||
p->done_fl = doneN == p->chN;
|
||||
|
||||
errLabel:
|
||||
if( rc != kOkRC )
|
||||
rc = cwLogError(rc,"multi-ch-wt-osc process failed.");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc_t test();
|
||||
|
||||
} //multi_ch_wt_seq_osc
|
||||
|
||||
|
||||
rc_t test( const test::test_args_t& args );
|
||||
|
||||
} // dsp
|
||||
} // cw
|
||||
|
Loading…
Reference in New Issue
Block a user