526 lines
14 KiB
C++
526 lines
14 KiB
C++
#include "cwCommon.h"
|
|
#include "cwLog.h"
|
|
#include "cwCommonImpl.h"
|
|
#include "cwTest.h"
|
|
#include "cwMem.h"
|
|
#include "cwFile.h"
|
|
#include "cwText.h"
|
|
#include "cwObject.h"
|
|
#include "cwAudioFile.h"
|
|
#include "cwUtility.h"
|
|
#include "cwFileSys.h"
|
|
#include "cwAudioFileOps.h"
|
|
#include "cwVectOps.h"
|
|
#include "cwMath.h"
|
|
#include "cwDsp.h"
|
|
#include "cwAudioTransforms.h"
|
|
|
|
namespace cw
|
|
{
|
|
namespace dsp
|
|
{
|
|
|
|
namespace wnd_func
|
|
{
|
|
|
|
idLabelPair_t wndLabelArray[] =
|
|
{
|
|
{ kHannWndId, "hann" },
|
|
{ kHammingWndId, "hamming" },
|
|
{ kTriangleWndId, "triangle" },
|
|
{ kKaiserWndId, "kaiser" },
|
|
{ kHannMatlabWndId, "hann_matlab" },
|
|
{ kUnityWndId, "unity" },
|
|
{ kInvalidWndId, "<invalid>" }
|
|
};
|
|
|
|
const char* wndIdToLabel( unsigned id )
|
|
{ return cw::idToLabel( wndLabelArray, id, kInvalidWndId ); }
|
|
|
|
unsigned wndLabelToId( const char* label )
|
|
{ return cw::labelToId( wndLabelArray, label, kInvalidWndId ); }
|
|
|
|
rc_t _test( const char* windowLabel, const double* wndV, unsigned maxWndN, unsigned wndN )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
wnd_func::fobj_t* p = nullptr;
|
|
|
|
unsigned wndId = wndLabelToId( windowLabel );
|
|
|
|
if((rc = create(p,wndId,maxWndN,wndN,3)) == kOkRC )
|
|
{
|
|
vop::print(p->wndV, p->wndN, "%f ", windowLabel);
|
|
|
|
printf("diff: %f\n", vop::sum_sq_diff( wndV, p->wndV, wndN));
|
|
|
|
destroy(p);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
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 };
|
|
double hamm_15[] = { 0.08,0.12555432, 0.25319469, 0.43764037, 0.64235963, 0.82680531, 0.95444568, 1.0, 0.95444568, 0.82680531,0.64235963, 0.43764037, 0.25319469, 0.12555432, 0.08 };
|
|
double hamm_16[] = { 0.08,0.11976909, 0.23219992, 0.39785218, 0.58808309, 0.77, 0.91214782, 0.9899479, 0.9899479 , 0.91214782,0.77, 0.58808309, 0.39785218, 0.23219992, 0.11976909, 0.08};
|
|
double tri_15[] = { 0.0, 0.14285714, 0.28571429, 0.42857143, 0.57142857, 0.71428571, 0.85714286, 1.0, 0.85714286, 0.71428571,0.57142857, 0.42857143, 0.28571429, 0.14285714, 0.0 };
|
|
double tri_16[] = { 0.0, 0.13333333, 0.26666667, 0.4, 0.53333333, 0.66666667, 0.8, 0.93333333, 0.93333333, 0.8, 0.66666667, 0.53333333, 0.4, 0.26666667, 0.13333333, 0.0 };
|
|
double ones_5[] = { 1.0, 1.0, 1.0, 1.0, 1.0 };
|
|
|
|
rc_t rc = kOkRC;
|
|
|
|
_test( "hann", hann_15, 15, 15);
|
|
_test( "hann", hann_16, 16, 16);
|
|
_test( "hamming", hamm_15, 15, 15);
|
|
_test( "hamming", hamm_16, 16, 16);
|
|
_test( "triangle", tri_15, 15, 15);
|
|
_test( "triangle", tri_16, 16, 16);
|
|
_test( "unity", ones_5, 5, 5);
|
|
|
|
if( rc != kOkRC )
|
|
cwLogError(rc,"Window test failed.");
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
namespace ola
|
|
{
|
|
rc_t test()
|
|
{
|
|
typedef float sample_t;
|
|
|
|
rc_t rc = kOkRC;
|
|
unsigned wndSmpCnt = 16;
|
|
unsigned hopSmpCnt = 4;
|
|
unsigned procSmpCnt = 2;
|
|
unsigned wndTypeId = wnd_func::kUnityWndId;
|
|
unsigned hopCnt = 8;
|
|
unsigned oSmpCnt = hopCnt * hopSmpCnt;
|
|
unsigned i,j,k;
|
|
|
|
sample_t cV[] = { 1,1,1,1, 2,2,2,2, 3,3,3,3, 4,4,4,4, 4,4,4,4, 4,4,4,4, 4,4,4,4, 4,4,4,4 };
|
|
sample_t* x = mem::allocZ<sample_t>(wndSmpCnt);
|
|
sample_t* y = mem::allocZ<sample_t>(oSmpCnt);
|
|
vop::fill(x,wndSmpCnt,1.0);
|
|
|
|
ola::fobj_t* p = nullptr;
|
|
|
|
if((rc = ola::create(p, wndSmpCnt, hopSmpCnt, procSmpCnt, wndTypeId )) == kOkRC )
|
|
{
|
|
|
|
// Each iteration represents a single audio cylce
|
|
// which sources/sinks procSmpCnt samples
|
|
for(i=0,j=0,k=0; k<oSmpCnt; i+=procSmpCnt)
|
|
{
|
|
j += procSmpCnt;
|
|
|
|
// if there are hopSmpCnt new samples available then there must
|
|
// be a new window of samples available -
|
|
if( j > hopSmpCnt )
|
|
{
|
|
j -= hopSmpCnt;
|
|
ola::exec(p,x,p->wndSmpCnt);
|
|
}
|
|
|
|
const sample_t* op;
|
|
|
|
// Get procSmpCnt samples from the output.
|
|
if( (op=ola::execOut(p)) != NULL )
|
|
{
|
|
assert( y + k + p->procSmpCnt <= y + oSmpCnt );
|
|
vop::copy<sample_t>(y+k, op, p->procSmpCnt);
|
|
k += p->procSmpCnt;
|
|
}
|
|
}
|
|
}
|
|
|
|
vop::print(cV,oSmpCnt,"%f ","Correct ");
|
|
vop::print(y, oSmpCnt,"%f ","Computed");
|
|
printf("diff:%f\n", vop::sum_sq_diff(cV,y,oSmpCnt));
|
|
|
|
ola::destroy(p);
|
|
mem::release(x);
|
|
mem::release(y);
|
|
return rc;
|
|
|
|
}
|
|
}
|
|
|
|
namespace shift_buf
|
|
{
|
|
rc_t test()
|
|
{
|
|
rc_t rc = kOkRC;
|
|
typedef float sample_t;
|
|
|
|
sample_t m[] =
|
|
{
|
|
1, 2, 3, 4, 5, 6, 7,
|
|
7, 8, 9,10,11,12,13,
|
|
13,14,15,16,17,18,19,
|
|
19,20,21,22,23,24,25,
|
|
25,26,27,28,29,30,31,
|
|
31,32,33,34,35,36,37,
|
|
37,38,39,40,41,42,43,
|
|
43,44,45,46,47,48,49
|
|
};
|
|
|
|
unsigned procSmpCnt = 5; // count of samples to be fed to the shift buffer on each cycle
|
|
unsigned hopSmpCnt = 6; // count of samples between shift buffer outputs
|
|
unsigned maxWndSmpCnt= 7;
|
|
unsigned wndSmpCnt = 7; // count of samples in each shift buffer output
|
|
|
|
unsigned iSmpCnt = 49; // count of samples in the input test signal
|
|
unsigned oColCnt = iSmpCnt / hopSmpCnt;
|
|
unsigned oSmpCnt = oColCnt * wndSmpCnt; // count of samples in the output test signal
|
|
unsigned i,j;
|
|
|
|
shift_buf::fobj_t* p = nullptr;
|
|
|
|
if((rc = shift_buf::create(p,procSmpCnt,maxWndSmpCnt,wndSmpCnt,hopSmpCnt)) == kOkRC )
|
|
{
|
|
sample_t* x = mem::allocZ<sample_t>(iSmpCnt);
|
|
sample_t* y = mem::allocZ<sample_t>(oSmpCnt);
|
|
|
|
vop::seq(x,iSmpCnt,1.0f,1.0f);
|
|
|
|
for(i=0,j=0; i<iSmpCnt; i+=procSmpCnt)
|
|
{
|
|
// Give the shift buffer a block of procSmpCnt samples.
|
|
// If it returns 'true' then it has hopSmpCnt new samples and
|
|
// a buffer of at least wndSmpCnt.
|
|
for(; shift_buf::exec( p, x + i, procSmpCnt ); j+=wndSmpCnt )
|
|
{
|
|
|
|
// cmShiftBufExec() returned true then there are wndSmpCnt samples available.
|
|
assert( y + j + wndSmpCnt <= y + oSmpCnt );
|
|
vop::copy(y + j, p->outV, wndSmpCnt );
|
|
|
|
vop::print(p->outV, wndSmpCnt, "%f ");
|
|
vop::print(m + j, wndSmpCnt, "%f ");
|
|
|
|
if( !vop::is_equal(p->outV, m+j, wndSmpCnt ))
|
|
{
|
|
rc = cwLogError(kTestFailRC,"shift_buf test failed.");
|
|
goto errLabel;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
mem::release(x);
|
|
mem::release(y);
|
|
shift_buf::destroy(p);
|
|
|
|
}
|
|
|
|
errLabel:
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
namespace pv_anl
|
|
{
|
|
rc_t test()
|
|
{
|
|
rc_t rc = kOkRC;
|
|
pv_anl::fobj_t* pva = nullptr;
|
|
pv_syn::fobj_t* pvs = nullptr;
|
|
unsigned procSmpCnt = 0;
|
|
float srate = 0;
|
|
float out_srate = 0;
|
|
unsigned wndSmpCnt = 0;
|
|
unsigned hopSmpCnt = 0;
|
|
unsigned flags = kCalcHzPvaFl;
|
|
unsigned wndTypeId = wnd_func::kHannWndId;
|
|
|
|
if((rc = create( pva, procSmpCnt, srate, wndSmpCnt, wndSmpCnt, hopSmpCnt, flags )) != kOkRC )
|
|
{
|
|
}
|
|
|
|
if((rc = create( pvs, procSmpCnt, out_srate, wndSmpCnt, hopSmpCnt, wndTypeId )) != kOkRC )
|
|
{
|
|
}
|
|
|
|
|
|
destroy(pva);
|
|
destroy(pvs);
|
|
|
|
return rc;
|
|
}
|
|
|
|
}
|
|
|
|
namespace wt_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_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;
|
|
}
|
|
}
|
|
|
|
/*
|
|
namespace spec_dist
|
|
{
|
|
rc_t _test_one( const object_t* arg, )
|
|
{
|
|
}
|
|
|
|
rc_t create( struct obj_str<T0,T1>*& p, unsigned binN, bool bypassFl=false, T1 ceiling=30, T1 expo=2, T1 thresh=60, T1 uprSlope=0, T1 lwrSlope=2, T1 mix=0 )
|
|
|
|
rc_t test( const object_t* args )
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
*/
|
|
}
|