Merge branch 'master' of gitea.larke.org:klarke/libcw
# Conflicts: # Makefile.am
This commit is contained in:
commit
1aba926fda
18
Makefile.am
18
Makefile.am
@ -4,8 +4,8 @@ libcwSRC =
|
|||||||
libcwHDR += src/libcw/cwCommon.h src/libcw/cwCommonImpl.h src/libcw/cwMem.h src/libcw/cwLog.h src/libcw/cwUtility.h
|
libcwHDR += src/libcw/cwCommon.h src/libcw/cwCommonImpl.h src/libcw/cwMem.h src/libcw/cwLog.h src/libcw/cwUtility.h
|
||||||
libcwSRC += src/libcw/cwCommonImpl.cpp src/libcw/cwMem.cpp src/libcw/cwLog.cpp src/libcw/cwUtility.cpp
|
libcwSRC += src/libcw/cwCommonImpl.cpp src/libcw/cwMem.cpp src/libcw/cwLog.cpp src/libcw/cwUtility.cpp
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwVectOps.h src/libcw/cwMtx.h
|
libcwHDR += src/libcw/cwString.h src/libcw/cwVectOps.h src/libcw/cwMtx.h
|
||||||
libcwSRC += src/libcw/cwMtx.cpp
|
libcwSRC += src/libcw/cwString.cpp src/libcw/cwMtx.cpp
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwFileSys.h src/libcw/cwText.h src/libcw/cwFile.h src/libcw/cwTime.h src/libcw/cwLex.h src/libcw/cwNumericConvert.h
|
libcwHDR += src/libcw/cwFileSys.h src/libcw/cwText.h src/libcw/cwFile.h src/libcw/cwTime.h src/libcw/cwLex.h src/libcw/cwNumericConvert.h
|
||||||
libcwSRC += src/libcw/cwFileSys.cpp src/libcw/cwText.cpp src/libcw/cwFile.cpp src/libcw/cwTime.cpp src/libcw/cwLex.cpp
|
libcwSRC += src/libcw/cwFileSys.cpp src/libcw/cwText.cpp src/libcw/cwFile.cpp src/libcw/cwTime.cpp src/libcw/cwLex.cpp
|
||||||
@ -22,8 +22,8 @@ libcwSRC += src/libcw/cwThread.cpp src/libcw/cwMutex.cpp src/libcw/cwThreadMach
|
|||||||
libcwHDR += src/libcw/cwMpScNbQueue.h src/libcw/cwSpScBuf.h src/libcw/cwSpScQueueTmpl.h
|
libcwHDR += src/libcw/cwMpScNbQueue.h src/libcw/cwSpScBuf.h src/libcw/cwSpScQueueTmpl.h
|
||||||
libcwSRC += src/libcw/cwSpScBuf.cpp src/libcw/cwSpScQueueTmpl.cpp
|
libcwSRC += src/libcw/cwSpScBuf.cpp src/libcw/cwSpScQueueTmpl.cpp
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwSvg.h src/libcw/cwAudioFile.h src/libcw/cwAudioFileOps.h
|
libcwHDR += src/libcw/cwAudioFile.h src/libcw/cwAudioFileOps.h
|
||||||
libcwSRC += src/libcw/cwSvg.cpp src/libcw/cwAudioFile.cpp src/libcw/cwAudioFileOps.cpp
|
libcwSRC += src/libcw/cwAudioFile.cpp src/libcw/cwAudioFileOps.cpp
|
||||||
|
|
||||||
if cwWEBSOCK
|
if cwWEBSOCK
|
||||||
libcwHDR += src/libcw/cwWebSock.h src/libcw/cwWebSockSvr.h
|
libcwHDR += src/libcw/cwWebSock.h src/libcw/cwWebSockSvr.h
|
||||||
@ -59,6 +59,9 @@ libcwSRC += src/libcw/cwSocket.cpp
|
|||||||
libcwHDR += src/libcw/cwTcpSocket.h src/libcw/cwTcpSocketSrv.h src/libcw/cwTcpSocketTest.h
|
libcwHDR += src/libcw/cwTcpSocket.h src/libcw/cwTcpSocketSrv.h src/libcw/cwTcpSocketTest.h
|
||||||
libcwSRC += src/libcw/cwTcpSocket.cpp src/libcw/cwTcpSocketSrv.cpp src/libcw/cwTcpSocketTest.cpp
|
libcwSRC += src/libcw/cwTcpSocket.cpp src/libcw/cwTcpSocketSrv.cpp src/libcw/cwTcpSocketTest.cpp
|
||||||
|
|
||||||
|
libcwHDR += src/libcw/cwDsp.h
|
||||||
|
libcwSRC += src/libcw/cwDsp.cpp
|
||||||
|
|
||||||
if cwWEBSOCK
|
if cwWEBSOCK
|
||||||
libcwHDR += src/libcw/cwIo.h src/libcw/cwIoTest.h
|
libcwHDR += src/libcw/cwIo.h src/libcw/cwIoTest.h
|
||||||
libcwSRC += src/libcw/cwIo.cpp src/libcw/cwIoTest.cpp
|
libcwSRC += src/libcw/cwIo.cpp src/libcw/cwIoTest.cpp
|
||||||
@ -67,6 +70,9 @@ endif
|
|||||||
libcwHDR += src/libcw/cwMdns.h src/libcw/cwEuCon.h src/libcw/cwDnsSd.h src/libcw/dns_sd/dns_sd.h src/libcw/dns_sd/dns_sd_print.h src/libcw/dns_sd/dns_sd_const.h src/libcw/dns_sd/fader.h src/libcw/dns_sd/rpt.h
|
libcwHDR += src/libcw/cwMdns.h src/libcw/cwEuCon.h src/libcw/cwDnsSd.h src/libcw/dns_sd/dns_sd.h src/libcw/dns_sd/dns_sd_print.h src/libcw/dns_sd/dns_sd_const.h src/libcw/dns_sd/fader.h src/libcw/dns_sd/rpt.h
|
||||||
libcwSRC += src/libcw/cwMdns.cpp src/libcw/cwEuCon.cpp src/libcw/cwDnsSd.cpp src/libcw/dns_sd/dns_sd.cpp src/libcw/dns_sd/dns_sd_print.cpp src/libcw/dns_sd/fader.cpp src/libcw/dns_sd/rpt.cpp
|
libcwSRC += src/libcw/cwMdns.cpp src/libcw/cwEuCon.cpp src/libcw/cwDnsSd.cpp src/libcw/dns_sd/dns_sd.cpp src/libcw/dns_sd/dns_sd_print.cpp src/libcw/dns_sd/fader.cpp src/libcw/dns_sd/rpt.cpp
|
||||||
|
|
||||||
|
if cwWEB
|
||||||
|
|
||||||
# libcwHDR += src/libcw/cwDataSets.h
|
else
|
||||||
# libcwSRC += src/libcw/cwDataSets.cpp
|
# libcwHDR += src/libcw/cwSvg.h src/libcw/cwDataSets.h
|
||||||
|
# libcwSRC += src/libcw/cwSvg.cpp src/libcw/cwDataSets.cpp
|
||||||
|
endif
|
||||||
|
@ -923,8 +923,9 @@ void cw::audio::buf::report(handle_t h)
|
|||||||
|
|
||||||
/// [cwAudioBufExample]
|
/// [cwAudioBufExample]
|
||||||
|
|
||||||
void cw::audio::buf::test()
|
cw::rc_t cw::audio::buf::test()
|
||||||
{
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
unsigned devIdx = 0;
|
unsigned devIdx = 0;
|
||||||
unsigned devCnt = 1 ;
|
unsigned devCnt = 1 ;
|
||||||
unsigned dspFrameCnt = 10;
|
unsigned dspFrameCnt = 10;
|
||||||
@ -1021,6 +1022,8 @@ void cw::audio::buf::test()
|
|||||||
cwLogInfo("\n");
|
cwLogInfo("\n");
|
||||||
|
|
||||||
destroy(h);
|
destroy(h);
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [cwAudioBufExample]
|
/// [cwAudioBufExample]
|
||||||
|
@ -232,7 +232,7 @@ namespace cw
|
|||||||
void report( handle_t h );
|
void report( handle_t h );
|
||||||
|
|
||||||
// Run a buffer usage simulation to test the class. cmAudioPortTest.c calls this function.
|
// Run a buffer usage simulation to test the class. cmAudioPortTest.c calls this function.
|
||||||
void test();
|
rc_t test();
|
||||||
|
|
||||||
//)
|
//)
|
||||||
|
|
||||||
|
@ -1590,7 +1590,7 @@ void cw::audio::device::alsa::deviceRealTimeReport(struct driver_str* drv, unsig
|
|||||||
//)
|
//)
|
||||||
|
|
||||||
//[
|
//[
|
||||||
void cw::audio::device::alsa::report( handle_t h )
|
cw::rc_t cw::audio::device::alsa::report( handle_t h )
|
||||||
{
|
{
|
||||||
alsa_t* p = _handleToPtr(h);
|
alsa_t* p = _handleToPtr(h);
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@ -1603,17 +1603,21 @@ void cw::audio::device::alsa::report( handle_t h )
|
|||||||
}
|
}
|
||||||
|
|
||||||
snd_config_update_free_global();
|
snd_config_update_free_global();
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cw::audio::device::alsa::report()
|
cw::rc_t cw::audio::device::alsa::report()
|
||||||
{
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
handle_t h;
|
handle_t h;
|
||||||
driver_t* d;
|
driver_t* d;
|
||||||
if( create(h,d) == kOkRC )
|
if( create(h,d) == kOkRC )
|
||||||
{
|
{
|
||||||
report(h);
|
rc = report(h);
|
||||||
destroy(h);
|
destroy(h);
|
||||||
}
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
//]
|
//]
|
||||||
|
@ -26,8 +26,8 @@ namespace cw
|
|||||||
bool deviceIsStarted( struct driver_str* drv, unsigned devIdx );
|
bool deviceIsStarted( struct driver_str* drv, unsigned devIdx );
|
||||||
void deviceRealTimeReport( struct driver_str* drv, unsigned devIdx );
|
void deviceRealTimeReport( struct driver_str* drv, unsigned devIdx );
|
||||||
|
|
||||||
void report(handle_t h );
|
rc_t report(handle_t h );
|
||||||
void report();
|
rc_t report();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@ namespace cw
|
|||||||
p->fp = nullptr;
|
p->fp = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mem::release(p->fn);
|
||||||
mem::release(p);
|
mem::release(p);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1296,6 +1297,62 @@ cw::rc_t cw::audiofile::getSumFloat( const char* fn, unsigned begFrmIdx, un
|
|||||||
cw::rc_t cw::audiofile::getSumDouble( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr )
|
cw::rc_t cw::audiofile::getSumDouble( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr )
|
||||||
{ return _getDouble( fn, begFrmIdx, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, afInfoPtr, true ); }
|
{ return _getDouble( fn, begFrmIdx, frmCnt, chIdx, chCnt, buf, actualFrmCntPtr, afInfoPtr, true ); }
|
||||||
|
|
||||||
|
cw::rc_t cw::audiofile::allocFloatBuf( const char* fn, float**& chBufRef, unsigned& chCntRef, unsigned& frmCntRef, info_t& afInfo, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
|
||||||
|
unsigned actualFrmCnt = 0;
|
||||||
|
|
||||||
|
frmCntRef = 0;
|
||||||
|
chCntRef = 0;
|
||||||
|
|
||||||
|
if((rc = getInfo(fn, &afInfo )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if( chCnt == 0 )
|
||||||
|
chCnt = afInfo.chCnt;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( chIdx + chCnt > afInfo.chCnt )
|
||||||
|
{
|
||||||
|
cwLogError(kInvalidArgRC,"Requested channel indexes %i to %i exceeds available channel count %i.",chIdx,chIdx+chCnt-1,afInfo,chCnt);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( frmCnt == 0 )
|
||||||
|
frmCnt = afInfo.frameCnt;
|
||||||
|
|
||||||
|
if( begFrmIdx + frmCnt > afInfo.frameCnt )
|
||||||
|
{
|
||||||
|
cwLogError(kInvalidArgRC,"Requested frames %i to %i exceeds available frame count %i.",begFrmIdx,begFrmIdx+frmCnt,afInfo.frameCnt);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
chBufRef = mem::allocZ< float* >(chCnt);
|
||||||
|
for(unsigned i=0; i<chCnt; ++i)
|
||||||
|
chBufRef[i] = mem::alloc<float>(frmCnt);
|
||||||
|
|
||||||
|
|
||||||
|
if((rc = getFloat(fn, begFrmIdx, frmCnt, chIdx, chCnt, chBufRef, &actualFrmCnt, nullptr)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
frmCntRef = actualFrmCnt;
|
||||||
|
chCntRef = chCnt;
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
if( rc != kOkRC )
|
||||||
|
cwLogError(rc,"Audio file allocFloat() failed.");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::audiofile::freeFloatBuf( float** floatBuf, unsigned chCnt )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<chCnt; ++i)
|
||||||
|
mem::release(floatBuf[i]);
|
||||||
|
mem::release(floatBuf);
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::audiofile::writeInt( handle_t h, unsigned frmCnt, unsigned chCnt, int** srcPtrPtr )
|
cw::rc_t cw::audiofile::writeInt( handle_t h, unsigned frmCnt, unsigned chCnt, int** srcPtrPtr )
|
||||||
@ -1623,6 +1680,21 @@ void cw::audiofile::printInfo( const info_t* infoPtr, log::handle_t logH )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::audiofile::reportInfo( const char* audioFn )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
info_t info;
|
||||||
|
|
||||||
|
if((rc = getInfo(audioFn,&info)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
printInfo(&info,log::globalHandle());
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::audiofile::report( handle_t h, log::handle_t logH, unsigned frmIdx, unsigned frmCnt )
|
cw::rc_t cw::audiofile::report( handle_t h, log::handle_t logH, unsigned frmIdx, unsigned frmCnt )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
@ -129,6 +129,10 @@ namespace cw
|
|||||||
rc_t getSumFloat( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr);
|
rc_t getSumFloat( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, float** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr);
|
||||||
rc_t getSumDouble( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr);
|
rc_t getSumDouble( const char* fn, unsigned begFrmIdx, unsigned frmCnt, unsigned chIdx, unsigned chCnt, double** buf, unsigned* actualFrmCntPtr, info_t* afInfoPtr);
|
||||||
|
|
||||||
|
// Allocate a buffer and read the file into it
|
||||||
|
rc_t allocFloatBuf( const char* fn, float**& chBufRef, unsigned& chCntRef, unsigned& frmCntRef, info_t& afInfoPtrRef, unsigned begFrmIdx=0, unsigned frmCnt=0, unsigned chIdx=0, unsigned chCnt=0 );
|
||||||
|
rc_t freeFloatBuf( float** floatBufRef, unsigned chCnt );
|
||||||
|
|
||||||
// Sample Writing Functions
|
// Sample Writing Functions
|
||||||
rc_t writeInt( handle_t h, unsigned frmCnt, unsigned chCnt, int** bufPtrPtr );
|
rc_t writeInt( handle_t h, unsigned frmCnt, unsigned chCnt, int** bufPtrPtr );
|
||||||
rc_t writeFloat( handle_t h, unsigned frmCnt, unsigned chCnt, float** bufPtrPtr );
|
rc_t writeFloat( handle_t h, unsigned frmCnt, unsigned chCnt, float** bufPtrPtr );
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include "cwUtility.h"
|
#include "cwUtility.h"
|
||||||
#include "cwFileSys.h"
|
#include "cwFileSys.h"
|
||||||
#include "cwAudioFileOps.h"
|
#include "cwAudioFileOps.h"
|
||||||
|
#include "cwVectOps.h"
|
||||||
|
#include "cwDsp.h"
|
||||||
|
|
||||||
cw::rc_t cw::afop::sine( const char* fn, double srate, unsigned bits, double hz, double gain, double secs )
|
cw::rc_t cw::afop::sine( const char* fn, double srate, unsigned bits, double hz, double gain, double secs )
|
||||||
{
|
{
|
||||||
@ -375,6 +377,9 @@ namespace cw
|
|||||||
xArgL[i].srcFadeOutFrmN = floor(argL[i].srcEndFadeSec * srate_Ref);
|
xArgL[i].srcFadeOutFrmN = floor(argL[i].srcEndFadeSec * srate_Ref);
|
||||||
xArgL[i].dstFrmIdx = floor(argL[i].dstBegSec * srate_Ref);
|
xArgL[i].dstFrmIdx = floor(argL[i].dstBegSec * srate_Ref);
|
||||||
|
|
||||||
|
//printf("cm beg:%f end:%f dst:%f gain:%f %s\n", argL[i].srcBegSec, argL[i].srcEndSec, argL[i].dstBegSec, argL[i].gain, argL[i].srcFn );
|
||||||
|
|
||||||
|
|
||||||
chN_Ref = std::max( chN_Ref, xArgL[i].afInfo.chCnt );
|
chN_Ref = std::max( chN_Ref, xArgL[i].afInfo.chCnt );
|
||||||
maxSrcFrmN_Ref = std::max( maxSrcFrmN_Ref, xArgL[i].srcFrmN );
|
maxSrcFrmN_Ref = std::max( maxSrcFrmN_Ref, xArgL[i].srcFrmN );
|
||||||
|
|
||||||
@ -482,7 +487,7 @@ cw::rc_t cw::afop::cutAndMix( const char* dstFn, unsigned dstBits, const char* s
|
|||||||
dstV = mem::allocZ<float>(dstFrmN*dstChN); // output signal buffer
|
dstV = mem::allocZ<float>(dstFrmN*dstChN); // output signal buffer
|
||||||
srcV = mem::alloc<float>(maxSrcFrmN*dstChN); // source signal buffer
|
srcV = mem::alloc<float>(maxSrcFrmN*dstChN); // source signal buffer
|
||||||
|
|
||||||
// create the src read buffer
|
// create the src read/ dst write buffer
|
||||||
for(unsigned i=0; i<dstChN; ++i)
|
for(unsigned i=0; i<dstChN; ++i)
|
||||||
{
|
{
|
||||||
dstChBufL[i] = dstV + (i*dstFrmN);
|
dstChBufL[i] = dstV + (i*dstFrmN);
|
||||||
@ -497,6 +502,7 @@ cw::rc_t cw::afop::cutAndMix( const char* dstFn, unsigned dstBits, const char* s
|
|||||||
unsigned srcFrmN = xArgL[i].srcFrmN;
|
unsigned srcFrmN = xArgL[i].srcFrmN;
|
||||||
unsigned srcChN = xArgL[i].afInfo.chCnt;
|
unsigned srcChN = xArgL[i].afInfo.chCnt;
|
||||||
|
|
||||||
|
|
||||||
// read the source segment
|
// read the source segment
|
||||||
if((rc = audiofile::getFloat( xArgL[i].srcFn, xArgL[i].srcFrmIdx, srcFrmN, chIdx, srcChN, srcChBufL, &actualFrmN, nullptr)) != kOkRC )
|
if((rc = audiofile::getFloat( xArgL[i].srcFn, xArgL[i].srcFrmIdx, srcFrmN, chIdx, srcChN, srcChBufL, &actualFrmN, nullptr)) != kOkRC )
|
||||||
{
|
{
|
||||||
@ -515,7 +521,7 @@ cw::rc_t cw::afop::cutAndMix( const char* dstFn, unsigned dstBits, const char* s
|
|||||||
for(unsigned k = 0; k<srcFrmN; ++k)
|
for(unsigned k = 0; k<srcFrmN; ++k)
|
||||||
{
|
{
|
||||||
assert( xArgL[i].dstFrmIdx + k < dstFrmN );
|
assert( xArgL[i].dstFrmIdx + k < dstFrmN );
|
||||||
dstChBufL[j][ xArgL[i].dstFrmIdx + k ] += srcChBufL[j][k];
|
dstChBufL[j][ xArgL[i].dstFrmIdx + k ] += xArgL[i].arg->gain * srcChBufL[j][k];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -582,15 +588,16 @@ cw::rc_t cw::afop::cutAndMix( const object_t* cfg )
|
|||||||
argL[i].dstBegSec = argL[i].srcBegSec; // By default the src is moved to the same location
|
argL[i].dstBegSec = argL[i].srcBegSec; // By default the src is moved to the same location
|
||||||
argL[i].srcBegFadeSec = crossFadeSec; // By default the beg/end fade is the global fade time.
|
argL[i].srcBegFadeSec = crossFadeSec; // By default the beg/end fade is the global fade time.
|
||||||
argL[i].srcEndFadeSec = crossFadeSec;
|
argL[i].srcEndFadeSec = crossFadeSec;
|
||||||
|
argL[i].gain = 1;
|
||||||
|
|
||||||
// parse the optional parameters
|
// parse the optional parameters
|
||||||
if((rc = o->getv_opt("dstBegSec", argL[i].dstBegSec, "srcBegFadeSec", argL[i].srcBegFadeSec, "srcEndFadeSec", argL[i].srcEndFadeSec )) != kOkRC )
|
if((rc = o->getv_opt("dstBegSec", argL[i].dstBegSec, "srcBegFadeSec", argL[i].srcBegFadeSec, "srcEndFadeSec", argL[i].srcEndFadeSec, "gain", argL[i].gain )) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kInvalidArgRC,"Invalid crossfade optional argument at argument index %i.",i);
|
rc = cwLogError(kInvalidArgRC,"Invalid crossfade optional argument at argument index %i.",i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("cm beg:%f end:%f dst:%f %s\n", argL[i].srcBegSec, argL[i].srcEndSec, argL[i].dstBegSec, argL[i].srcFn );
|
//printf("cm beg:%f end:%f dst:%f gain:%f %s\n", argL[i].srcBegSec, argL[i].srcEndSec, argL[i].dstBegSec, argL[i].gain, argL[i].srcFn );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,7 +636,9 @@ cw::rc_t cw::afop::parallelMix( const char* dstFn, unsigned dstBits, const char*
|
|||||||
cmArgL[i].srcEndSec = argL[i].srcEndSec + argL[i].fadeOutSec;
|
cmArgL[i].srcEndSec = argL[i].srcEndSec + argL[i].fadeOutSec;
|
||||||
cmArgL[i].srcBegFadeSec = fadeInSec;
|
cmArgL[i].srcBegFadeSec = fadeInSec;
|
||||||
cmArgL[i].srcEndFadeSec = argL[i].fadeOutSec;
|
cmArgL[i].srcEndFadeSec = argL[i].fadeOutSec;
|
||||||
cmArgL[i].dstBegSec = dstBegSec;
|
//cmArgL[i].dstBegSec = dstBegSec;
|
||||||
|
cmArgL[i].dstBegSec = argL[i].srcBegSec - argL[0].srcBegSec;
|
||||||
|
cmArgL[i].gain = argL[i].gain;
|
||||||
|
|
||||||
dstBegSec += argL[i].srcEndSec - argL[i].srcBegSec;
|
dstBegSec += argL[i].srcEndSec - argL[i].srcBegSec;
|
||||||
fadeInSec = argL[i].fadeOutSec;
|
fadeInSec = argL[i].fadeOutSec;
|
||||||
@ -670,17 +679,17 @@ cw::rc_t cw::afop::parallelMix( const object_t* cfg )
|
|||||||
// parse the non-optional parameters
|
// parse the non-optional parameters
|
||||||
if((rc = o->getv("srcBegSec", argL[i].srcBegSec, "srcEndSec", argL[i].srcEndSec, "fadeOutSec", argL[i].fadeOutSec, "srcFn", argL[i].srcFn )) != kOkRC )
|
if((rc = o->getv("srcBegSec", argL[i].srcBegSec, "srcEndSec", argL[i].srcEndSec, "fadeOutSec", argL[i].fadeOutSec, "srcFn", argL[i].srcFn )) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kInvalidArgRC,"Invalid crossfade argument at argument index %i.",i);
|
rc = cwLogError(kInvalidArgRC,"Invalid xform app argument at argument index %i.",i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
argL[i].gain = 1;
|
||||||
|
|
||||||
// parse the optional parameters
|
// parse the optional parameters
|
||||||
if((rc = o->getv_opt("dstBegSec", argL[i].dstBegSec, "srcBegFadeSec", argL[i].srcBegFadeSec, "srcEndFadeSec", argL[i].srcEndFadeSec )) != kOkRC )
|
if((rc = o->getv_opt("gain", argL[i].gain )) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kInvalidArgRC,"Invalid crossfade optional argument at argument index %i.",i);
|
rc = cwLogError(kInvalidArgRC,"Invalid xform app optional argument at argument index %i.",i);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("beg:%f end:%f fade:%f %s\n", argL[i].srcBegSec, argL[i].srcEndSec, argL[i].fadeOutSec, argL[i].srcFn );
|
//printf("beg:%f end:%f fade:%f %s\n", argL[i].srcBegSec, argL[i].srcEndSec, argL[i].fadeOutSec, argL[i].srcFn );
|
||||||
@ -704,6 +713,222 @@ cw::rc_t cw::afop::parallelMix( const object_t* cfg )
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::afop::transformApp( const object_t* cfg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const char* srcDir = nullptr;
|
||||||
|
const char* dryFn = nullptr;
|
||||||
|
const char* dstPreFn = nullptr;
|
||||||
|
const char* dstRevFn = nullptr;
|
||||||
|
unsigned dstBits = 16;
|
||||||
|
const object_t* argNodeL = nullptr;
|
||||||
|
bool irEnableFl=false;
|
||||||
|
const char* irFn = nullptr;
|
||||||
|
double irScale = 1;
|
||||||
|
|
||||||
|
char* expSrcDir = nullptr;
|
||||||
|
char* expDryFn = nullptr;
|
||||||
|
char* expDstPreFn = nullptr;
|
||||||
|
char* expDstRevFn = nullptr;
|
||||||
|
char* expIrFn = nullptr;
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
// read the top level cfg record
|
||||||
|
if((rc = cfg->getv("dstPreFn",dstPreFn,"dstRevFn",dstRevFn,"dstBits",dstBits,"srcDir",srcDir,"argL",argNodeL,"dryFn",dryFn,"irEnableFl",irEnableFl,"irFn",irFn,"irScale",irScale)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
|
||||||
|
expSrcDir = filesys::expandPath(srcDir);
|
||||||
|
expDryFn = filesys::expandPath(dryFn);
|
||||||
|
expDstPreFn = filesys::expandPath(dstPreFn);
|
||||||
|
expDstRevFn = filesys::expandPath(dstRevFn);
|
||||||
|
|
||||||
|
|
||||||
|
if( argNodeL == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"No crossfades were specified.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned argN = argNodeL->child_count() * 2;
|
||||||
|
parallelMixArg_t argL[ argN ];
|
||||||
|
|
||||||
|
// for each source file
|
||||||
|
for(i=0; i<argNodeL->child_count(); ++i)
|
||||||
|
{
|
||||||
|
const object_t* o = argNodeL->child_ele(i);
|
||||||
|
|
||||||
|
unsigned j = i*2;
|
||||||
|
|
||||||
|
// parse the non-optional parameters
|
||||||
|
if((rc = o->getv("srcBegSec", argL[j].srcBegSec, "srcEndSec", argL[j].srcEndSec, "fadeOutSec", argL[j].fadeOutSec, "srcFn", argL[j].srcFn )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"Invalid xform app argument at argument index %i.",i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
argL[j].gain = 1;
|
||||||
|
|
||||||
|
// parse the optional parameters
|
||||||
|
if((rc = o->getv_opt("wetGain", argL[j].gain )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"Invalid xform app optional argument at argument index %i.",i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// expand the source file name
|
||||||
|
argL[j].srcFn = filesys::makeFn(expSrcDir, argL[j].srcFn, NULL, NULL);
|
||||||
|
|
||||||
|
// form the dry file name
|
||||||
|
argL[j+1] = argL[j];
|
||||||
|
argL[j+1].srcFn = expDryFn;
|
||||||
|
argL[j+1].gain = 1.0 - argL[j].gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
// call cross-fader
|
||||||
|
rc = parallelMix( expDstPreFn, dstBits, "", argL, argN );
|
||||||
|
|
||||||
|
for(unsigned i=0; i<argN; i+=2)
|
||||||
|
mem::release( const_cast<char*&>(argL[i].srcFn));
|
||||||
|
|
||||||
|
if( rc == kOkRC && irEnableFl )
|
||||||
|
{
|
||||||
|
expIrFn = filesys::expandPath(irFn);
|
||||||
|
rc = convolve( expDstRevFn, dstBits, expDstPreFn, expIrFn, irScale );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mem::release(expSrcDir);
|
||||||
|
mem::release(expDryFn);
|
||||||
|
mem::release(expDstPreFn);
|
||||||
|
mem::release(expDstRevFn);
|
||||||
|
mem::release(expIrFn);
|
||||||
|
|
||||||
|
if( rc != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Transform-app failed.");
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::afop::convolve( const char* dstFn, unsigned dstBits, const char* srcFn, const char* impulseResponseFn, float irScale )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
float** hChBuf = nullptr;
|
||||||
|
unsigned hChN = 0;
|
||||||
|
unsigned hFrmN = 0;
|
||||||
|
double hSrate = 0;
|
||||||
|
float** xChBuf = nullptr;
|
||||||
|
unsigned xChN = 0;
|
||||||
|
unsigned xFrmN = 0;
|
||||||
|
audiofile::info_t info;
|
||||||
|
|
||||||
|
audiofile::reportInfo(impulseResponseFn);
|
||||||
|
audiofile::reportInfo(srcFn);
|
||||||
|
|
||||||
|
// read the impulse response audio file
|
||||||
|
if((rc = audiofile::allocFloatBuf(impulseResponseFn, hChBuf, hChN, hFrmN, info)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"The impulse audio file read failed on '%s'.", cwStringNullGuard(impulseResponseFn));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
hSrate = info.srate;
|
||||||
|
|
||||||
|
// read the source audio file
|
||||||
|
if((rc = audiofile::allocFloatBuf(srcFn, xChBuf, xChN, xFrmN, info)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"The source audio file read failed on '%s'.", cwStringNullGuard(srcFn));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the sample rate of impulse response and src audio signals must be the same
|
||||||
|
if( hSrate != info.srate )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"The soure file sample rate %f does not match the impulse response sample rate %f.",info.srate,hSrate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// allocate the output buffer
|
||||||
|
float* yChBuf[ xChN ];
|
||||||
|
unsigned yFrmN = xFrmN + hFrmN;
|
||||||
|
for(unsigned i=0; i<xChN; ++i)
|
||||||
|
yChBuf[i] = mem::allocZ<float>( yFrmN );
|
||||||
|
|
||||||
|
//printf("xFrmN:%i xChN:%i hFrmN:%i hChN:%i yFrmN:%i\n",xFrmN,xChN,hFrmN,hChN,yFrmN);
|
||||||
|
|
||||||
|
// scale the impulse response
|
||||||
|
for(unsigned i=0; i<hChN; ++i)
|
||||||
|
vop::mul( hChBuf[i], irScale, hFrmN );
|
||||||
|
|
||||||
|
// for each source channel
|
||||||
|
for(unsigned i=0; i<xChN && rc == kOkRC; ++i)
|
||||||
|
{
|
||||||
|
unsigned j = i >= hChN ? 0 : i; // select the impulse response channel
|
||||||
|
|
||||||
|
// convolve this channel with the impulse response and store into the output buffer
|
||||||
|
rc = dsp::convolve::apply( xChBuf[i], xFrmN, hChBuf[j], hFrmN, yChBuf[i], yFrmN );
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the output file.
|
||||||
|
if( rc == kOkRC )
|
||||||
|
rc = audiofile::writeFileFloat( dstFn, info.srate, dstBits, yFrmN, xChN, yChBuf);
|
||||||
|
|
||||||
|
|
||||||
|
// release the output buffer
|
||||||
|
for(unsigned i=0; i<xChN; ++i)
|
||||||
|
mem::release( yChBuf[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
if(rc != kOkRC )
|
||||||
|
cwLogError(rc,"Audio file convolve failed.");
|
||||||
|
|
||||||
|
audiofile::freeFloatBuf(hChBuf, hChN );
|
||||||
|
audiofile::freeFloatBuf(xChBuf, xChN );
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::afop::convolve( const object_t* cfg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const char* srcFn = nullptr;
|
||||||
|
const char* dstFn = nullptr;
|
||||||
|
const char* irFn = nullptr;
|
||||||
|
float irScale = 1.0;
|
||||||
|
unsigned dstBits = 16;
|
||||||
|
|
||||||
|
|
||||||
|
// read the top level cfg record
|
||||||
|
if((rc = cfg->getv("dstFn",dstFn,"dstBits",dstBits,"srcFn",srcFn,"irFn",irFn,"irScale",irScale)) != kOkRC )
|
||||||
|
{
|
||||||
|
cwLogError(rc,"convolve() arg. parse failed.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char* sFn = filesys::expandPath(srcFn);
|
||||||
|
char* dFn = filesys::expandPath(dstFn);
|
||||||
|
char* iFn = filesys::expandPath(irFn);
|
||||||
|
|
||||||
|
rc = convolve( dFn, dstBits, sFn, iFn, irScale );
|
||||||
|
|
||||||
|
mem::release(sFn);
|
||||||
|
mem::release(dFn);
|
||||||
|
mem::release(iFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::afop::test( const object_t* cfg )
|
cw::rc_t cw::afop::test( const object_t* cfg )
|
||||||
{
|
{
|
||||||
|
@ -19,7 +19,7 @@ namespace cw
|
|||||||
rc_t selectToFile( const object_t* cfg );
|
rc_t selectToFile( const object_t* cfg );
|
||||||
|
|
||||||
|
|
||||||
// Cross fader
|
// Arbitrary cross fader
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* srcFn; // source audio file name
|
const char* srcFn; // source audio file name
|
||||||
double srcBegSec; // source clip begin
|
double srcBegSec; // source clip begin
|
||||||
@ -27,22 +27,31 @@ namespace cw
|
|||||||
double srcBegFadeSec; // length of fade in (fade begins at srcBegSec and ends at srcBegSec+srcBegFadeSec)
|
double srcBegFadeSec; // length of fade in (fade begins at srcBegSec and ends at srcBegSec+srcBegFadeSec)
|
||||||
double srcEndFadeSec; // length of fade out (fade begins at srcEndSec-srcEndFadeSec and ends at srcEndSec)
|
double srcEndFadeSec; // length of fade out (fade begins at srcEndSec-srcEndFadeSec and ends at srcEndSec)
|
||||||
double dstBegSec; // clip output location
|
double dstBegSec; // clip output location
|
||||||
|
double gain; // scale the signal
|
||||||
} cutMixArg_t;
|
} cutMixArg_t;
|
||||||
|
|
||||||
rc_t cutAndMix( const char* outFn, unsigned outBits, const char* srcDir, const cutMixArg_t* argL, unsigned argN );
|
rc_t cutAndMix( const char* outFn, unsigned outBits, const char* srcDir, const cutMixArg_t* argL, unsigned argN );
|
||||||
rc_t cutAndMix( const object_t* cfg );
|
rc_t cutAndMix( const object_t* cfg );
|
||||||
|
|
||||||
|
// Given a collection of overlapping tracks fade in/out sections of the tracks at specified times.
|
||||||
|
// This is a wrapper around cutAndMix()
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
const char* srcFn;
|
const char* srcFn;
|
||||||
double srcBegSec;
|
double srcBegSec;
|
||||||
double srcEndSec;
|
double srcEndSec;
|
||||||
double fadeOutSec;
|
double fadeOutSec;
|
||||||
|
double gain;
|
||||||
} parallelMixArg_t;
|
} parallelMixArg_t;
|
||||||
|
|
||||||
rc_t parallelMix( const char* dstFn, unsigned dstBits, const char* srcDir, const parallelMixArg_t* argL, unsigned argN );
|
rc_t parallelMix( const char* dstFn, unsigned dstBits, const char* srcDir, const parallelMixArg_t* argL, unsigned argN );
|
||||||
rc_t parallelMix( const object_t* cfg );
|
rc_t parallelMix( const object_t* cfg );
|
||||||
|
|
||||||
|
rc_t transformApp( const object_t* cfg );
|
||||||
|
|
||||||
|
rc_t convolve( const char* dstFn, unsigned dstBits, const char* srcFn, const char* impulseResponseFn, float irScale=1 );
|
||||||
|
rc_t convolve( const object_t* cfg );
|
||||||
|
|
||||||
rc_t test( const object_t* cfg );
|
rc_t test( const object_t* cfg );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
#include <limits> // std::numeric_limits<
|
#include <limits> // std::numeric_limits<
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cmath>
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
|
|
||||||
#if defined(OS_LINUX) || defined(OS_OSX)
|
#if defined(OS_LINUX) || defined(OS_OSX)
|
||||||
#define cwPOSIX_FILE_SYS
|
#define cwPOSIX_FILE_SYS
|
||||||
@ -176,7 +179,28 @@ namespace cw
|
|||||||
void sleepUs( unsigned us ); // sleep seconds
|
void sleepUs( unsigned us ); // sleep seconds
|
||||||
void sleepNs( unsigned ns ); // sleep nanoseconds
|
void sleepNs( unsigned ns ); // sleep nanoseconds
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
bool is_even( const T& t )
|
||||||
|
{
|
||||||
|
assert( is_integral(t) );
|
||||||
|
return (t % 2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(cwWEB)
|
||||||
|
template< typename T>
|
||||||
|
bool is_int(const T& x)
|
||||||
|
{ return false; }
|
||||||
|
|
||||||
|
template<> inline bool is_int<signed char>( const signed char& x ) { return true; }
|
||||||
|
template<> inline bool is_int<unsigned char>( const unsigned char& x ) { return true; }
|
||||||
|
template<> inline bool is_int<signed short>( const signed short& x ) { return true; }
|
||||||
|
template<> inline bool is_int<unsigned short>( const unsigned short& x ) { return true; }
|
||||||
|
template<> inline bool is_int<signed long>( const signed long& x ) { return true; }
|
||||||
|
template<> inline bool is_int<unsigned long>( const unsigned long& x ) { return true; }
|
||||||
|
template<> inline bool is_int<signed long long>( const signed long long& x ) { return true; }
|
||||||
|
template<> inline bool is_int<unsigned long long>( const unsigned long long& x ) { return true; }
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
144
cwDsp.cpp
Normal file
144
cwDsp.cpp
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwMem.h"
|
||||||
|
#include "cwUtility.h"
|
||||||
|
#include "cwVectOps.h"
|
||||||
|
#include "cwDsp.h"
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------------------
|
||||||
|
// fft
|
||||||
|
//
|
||||||
|
|
||||||
|
cw::rc_t cw::dsp::fft::test()
|
||||||
|
{
|
||||||
|
typedef float real_t;
|
||||||
|
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned flags = kToPolarFl;
|
||||||
|
unsigned xN = 16;
|
||||||
|
real_t srate = xN;
|
||||||
|
real_t hz = 1;
|
||||||
|
real_t xV[xN];
|
||||||
|
struct ptr_str<real_t>* p = create<real_t>(xN,flags);
|
||||||
|
|
||||||
|
if(p != nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"FFT procedure allocation failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
vop::zero(xV,xN);
|
||||||
|
vop::sine(xV,xN,srate,hz);
|
||||||
|
|
||||||
|
exec(p,xV,xN);
|
||||||
|
|
||||||
|
vop::print( xV, xN, "%f ", "sin " );
|
||||||
|
vop::print( magn(p), bin_count(p), "%f ", "mag " );
|
||||||
|
vop::print( phase(p), bin_count(p), "%f ", "phs " );
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
destroy(p);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------------------
|
||||||
|
// ifft
|
||||||
|
//
|
||||||
|
|
||||||
|
cw::rc_t cw::dsp::ifft::test()
|
||||||
|
{
|
||||||
|
typedef double real_t;
|
||||||
|
|
||||||
|
struct fft::ptr_str<real_t>* ft = nullptr;
|
||||||
|
struct ptr_str<real_t>* ift = nullptr;
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned xN = 16;
|
||||||
|
real_t xV[xN];
|
||||||
|
|
||||||
|
if( (ft = fft::create<real_t>(xN,fft::kToPolarFl)) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"FFT procedure allocation failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ift = create<real_t>(fft::bin_count(ft))) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"IFFT procedure allocation failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
vop::zero(xV,xN);
|
||||||
|
vop::sine(xV,xN,(double)xN,1.0);
|
||||||
|
|
||||||
|
fft::exec(ft,xV,xN);
|
||||||
|
|
||||||
|
|
||||||
|
exec(ift, fft::magn(ft), fft::phase(ft) );
|
||||||
|
|
||||||
|
vop::print( xV, xN, "%f ", "sin " );
|
||||||
|
vop::print( magn(ft), fft::bin_count(ft), "%f ", "mag " );
|
||||||
|
vop::print( phase(ft), fft::bin_count(ft), "%f ", "phs " );
|
||||||
|
vop::print( out(ift), out_count(ift), "%f ", "sig " );
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
destroy(ft);
|
||||||
|
destroy(ift);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------------------
|
||||||
|
// convolve
|
||||||
|
//
|
||||||
|
|
||||||
|
cw::rc_t cw::dsp::convolve::test()
|
||||||
|
{
|
||||||
|
typedef float real_t;
|
||||||
|
|
||||||
|
real_t hV[] = { 1, .5, .25, .1, .05 };
|
||||||
|
unsigned hN = sizeof(hV) / sizeof(hV[0]);
|
||||||
|
real_t xV[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 };
|
||||||
|
unsigned xN = 4; //sizeof(xV) / sizeof(xV[0]);
|
||||||
|
real_t yV[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
unsigned yN = sizeof(yV) / sizeof(yV[0]);
|
||||||
|
// correct output from apply: real_t zV[] = { 1., 0.5, 0.25,0.1, 1.05,0.5, 0.25,0.1, 1.05,0.5, 0.25,0.1, 0.05,0.0, 0.0 };
|
||||||
|
|
||||||
|
|
||||||
|
ptr_str<real_t>* p = create(hV,hN,xN);
|
||||||
|
|
||||||
|
exec(p,xV,xN);
|
||||||
|
|
||||||
|
vop::print( p->outV, p->outN , "%f ", "out ");
|
||||||
|
vop::print( p->olaV, p->olaN, "%f ", "ola " );
|
||||||
|
|
||||||
|
exec(p,xV+4,xN);
|
||||||
|
|
||||||
|
vop::print( p->outV, p->outN , "%f ", "out ");
|
||||||
|
vop::print( p->olaV, p->olaN, "%f ", "ola " );
|
||||||
|
|
||||||
|
exec(p,xV+8,xN);
|
||||||
|
|
||||||
|
vop::print( p->outV, p->outN , "%f ", "out ");
|
||||||
|
vop::print( p->olaV, p->olaN, "%f ", "ola " );
|
||||||
|
|
||||||
|
xN = sizeof(xV) / sizeof(xV[0]);
|
||||||
|
|
||||||
|
apply(xV,xN,hV,hN,yV,yN);
|
||||||
|
vop::print( yV, yN , "%4.2f ", "yV ");
|
||||||
|
|
||||||
|
destroy(p);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 0.5 0.25 0.1 1.05 0.5 0.25 0.1 1.05 0.5 0.25 0.1 0.05 0.0. 0. ]
|
||||||
|
// 1.0 0.5 0.25 0.1 1.05 0.5 0.25 0.1 1.05 0.5 0.25 0.1 1.05 1.0 0.75 0.
|
587
cwDsp.h
Normal file
587
cwDsp.h
Normal file
@ -0,0 +1,587 @@
|
|||||||
|
#ifndef cwDsp_H
|
||||||
|
#define cwDsp_H
|
||||||
|
|
||||||
|
#include <fftw3.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace dsp
|
||||||
|
{
|
||||||
|
typedef std::complex<double> complex_d_t;
|
||||||
|
typedef std::complex<float> complex_f_t;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Window functions
|
||||||
|
//
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T kaiser_beta_from_sidelobe_reject( const T& sidelobeRejectDb )
|
||||||
|
{
|
||||||
|
double beta;
|
||||||
|
|
||||||
|
if( sidelobeRejectDb < 13.26 )
|
||||||
|
sidelobeRejectDb = 13.26;
|
||||||
|
else
|
||||||
|
if( sidelobeRejectDb > 120.0)
|
||||||
|
sidelobeRejectDb = 120.0;
|
||||||
|
|
||||||
|
if( sidelobeRejectDb < 60.0 )
|
||||||
|
beta = (0.76609 * pow(sidelobeRejectDb - 13.26,0.4)) + (0.09834*(sidelobeRejectDb-13.26));
|
||||||
|
else
|
||||||
|
beta = 0.12438 * (sidelobeRejectDb + 6.3);
|
||||||
|
|
||||||
|
return beta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T kaiser_freq_resolution_factor( const T& sidelobeRejectDb )
|
||||||
|
{ return (6.0 * (sidelobeRejectDb + 12.0))/155.0; }
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T* kaiser( T* dbp, unsigned n, const T& beta )
|
||||||
|
{
|
||||||
|
bool zeroFl = false;
|
||||||
|
int M = 0;
|
||||||
|
double den = cmBessel0(beta); // wnd func denominator
|
||||||
|
int cnt = n;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
assert( n >= 3 );
|
||||||
|
|
||||||
|
// force ele cnt to be odd
|
||||||
|
if( is_even(cnt) )
|
||||||
|
{
|
||||||
|
cnt--;
|
||||||
|
zeroFl = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// at this point cnt is odd and >= 3
|
||||||
|
|
||||||
|
// calc half the window length
|
||||||
|
M = (int)((cnt - 1.0)/2.0);
|
||||||
|
|
||||||
|
double Msqrd = M*M;
|
||||||
|
|
||||||
|
for(i=0; i<cnt; i++)
|
||||||
|
{
|
||||||
|
double v0 = (double)(i - M);
|
||||||
|
|
||||||
|
double num = cmBessel0(beta * sqrt(1.0 - ((v0*v0)/Msqrd)));
|
||||||
|
|
||||||
|
dbp[i] = (T)(num/den);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if( zeroFl )
|
||||||
|
dbp[cnt] = 0.0; // zero the extra element in the output array
|
||||||
|
|
||||||
|
return dbp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T* gaussian( T* dbp, unsigned dn, double mean, double variance )
|
||||||
|
{
|
||||||
|
|
||||||
|
int M = dn-1;
|
||||||
|
double sqrt2pi = sqrt(2.0*M_PI);
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for(i=0; i<dn; i++)
|
||||||
|
{
|
||||||
|
double arg = ((((double)i/M) - 0.5) * M);
|
||||||
|
|
||||||
|
arg = pow( (double)(arg-mean), 2.0);
|
||||||
|
|
||||||
|
arg = exp( -arg / (2.0*variance));
|
||||||
|
|
||||||
|
dbp[i] = (T)(arg / (sqrt(variance) * sqrt2pi));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T* hamming( T* dbp, unsigned dn )
|
||||||
|
{
|
||||||
|
const T* dep = dbp + dn;
|
||||||
|
T* dp = dbp;
|
||||||
|
double fact = 2.0 * M_PI / (dn-1);
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for(i=0; dbp < dep; ++i )
|
||||||
|
*dbp++ = (T)(.54 - (.46 * cos(fact*i)));
|
||||||
|
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T* hann( T* dbp, unsigned dn )
|
||||||
|
{
|
||||||
|
const T* dep = dbp + dn;
|
||||||
|
T* dp = dbp;
|
||||||
|
double fact = 2.0 * M_PI / (dn-1);
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for(i=0; dbp < dep; ++i )
|
||||||
|
*dbp++ = (T)(.5 - (.5 * cos(fact*i)));
|
||||||
|
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T* hann_matlab( T* dbp, unsigned dn )
|
||||||
|
{
|
||||||
|
const T* dep = dbp + dn;
|
||||||
|
T* dp = dbp;
|
||||||
|
double fact = 2.0 * M_PI / (dn+1);
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for(i=0; dbp < dep; ++i )
|
||||||
|
*dbp++ = (T)(0.5*(1.0-cos(fact*(i+1))));
|
||||||
|
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T* triangle( T* dbp, unsigned dn )
|
||||||
|
{
|
||||||
|
unsigned n = dn/2;
|
||||||
|
T incr = 1.0/n;
|
||||||
|
|
||||||
|
seq(dbp,n,0,incr);
|
||||||
|
|
||||||
|
seq(dbp+n,dn-n,1,-incr);
|
||||||
|
|
||||||
|
return dbp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T* gauss_window( T* dbp, unsigned dn, double arg )
|
||||||
|
{
|
||||||
|
const T* dep = dbp + dn;
|
||||||
|
T* rp = dbp;
|
||||||
|
int N = (dep - dbp) - 1;
|
||||||
|
int n = -N/2;
|
||||||
|
|
||||||
|
if( N == 0 )
|
||||||
|
*dbp = 1.0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while( dbp < dep )
|
||||||
|
{
|
||||||
|
double a = (arg * n++) / (N/2);
|
||||||
|
|
||||||
|
*dbp++ = (T)exp( -(a*a)/2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// FFT
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace fft
|
||||||
|
{
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kToPolarFl = 0x01, // convert to polar (magn./phase)
|
||||||
|
kToRectFl = 0x02, // convert to rect (real/imag)
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct ptr_str
|
||||||
|
{
|
||||||
|
unsigned flags;
|
||||||
|
|
||||||
|
T* inV;
|
||||||
|
std::complex<T>* cplxV;
|
||||||
|
|
||||||
|
T* magV;
|
||||||
|
T* phsV;
|
||||||
|
|
||||||
|
unsigned inN;
|
||||||
|
unsigned binN;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
fftw_plan dplan;
|
||||||
|
fftwf_plan fplan;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct ptr_str<T>* create( unsigned xN, unsigned flags=kToPolarFl )
|
||||||
|
{
|
||||||
|
struct ptr_str<T>* p = mem::allocZ< ptr_str<T> >(1);
|
||||||
|
|
||||||
|
p->flags = flags;
|
||||||
|
p->inN = xN;
|
||||||
|
p->binN = xN/2 + 1;
|
||||||
|
p->magV = mem::allocZ<T>(p->binN);
|
||||||
|
p->phsV = mem::allocZ<T>(p->binN);
|
||||||
|
|
||||||
|
if( std::is_same<T,float>::value )
|
||||||
|
{
|
||||||
|
p->inV = (T*)fftwf_malloc( sizeof(T)*xN );
|
||||||
|
p->cplxV = (std::complex<T>*)fftwf_malloc( sizeof(std::complex<T>)*xN);
|
||||||
|
p->u.fplan = fftwf_plan_dft_r2c_1d((int)xN, (float*)p->inV, reinterpret_cast<fftwf_complex*>(p->cplxV), FFTW_MEASURE );
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->inV = (T*)fftw_malloc( sizeof(T)*xN );
|
||||||
|
p->cplxV = (std::complex<T>*)fftw_malloc( sizeof(std::complex<T>)*xN);
|
||||||
|
p->u.dplan = fftw_plan_dft_r2c_1d((int)xN, (double*)p->inV, reinterpret_cast<fftw_complex*>(p->cplxV), FFTW_MEASURE );
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
rc_t destroy( struct ptr_str<T>*& p )
|
||||||
|
{
|
||||||
|
if( p == nullptr )
|
||||||
|
return kOkRC;
|
||||||
|
|
||||||
|
if( std::is_same<T,float>::value )
|
||||||
|
{
|
||||||
|
fftwf_destroy_plan( p->u.fplan );
|
||||||
|
fftwf_free(p->inV);
|
||||||
|
fftwf_free(p->cplxV);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fftw_destroy_plan( p->u.dplan );
|
||||||
|
fftw_free(p->inV);
|
||||||
|
fftw_free(p->cplxV);
|
||||||
|
}
|
||||||
|
|
||||||
|
p->u.dplan = nullptr;
|
||||||
|
mem::release(p->magV);
|
||||||
|
mem::release(p->phsV);
|
||||||
|
mem::release(p);
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
rc_t exec( struct ptr_str<T>* p, const T* xV, unsigned xN )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
assert( xN <= p->inN);
|
||||||
|
|
||||||
|
// if the incoming vector size is less than the FT buffer size
|
||||||
|
// then zero the extra values at the end of the buffer
|
||||||
|
if( xN < p->inN )
|
||||||
|
memset(p->inV + xN, 0, sizeof(T) * (p->inN-xN) );
|
||||||
|
|
||||||
|
// copy the incoming samples into the input buffer
|
||||||
|
memcpy(p->inV,xV,sizeof(T)*xN);
|
||||||
|
|
||||||
|
// execute the FT
|
||||||
|
if( std::is_same<T,float>::value )
|
||||||
|
fftwf_execute(p->u.fplan);
|
||||||
|
else
|
||||||
|
fftw_execute(p->u.dplan);
|
||||||
|
|
||||||
|
// convert to polar
|
||||||
|
if( cwIsFlag(p->flags,kToPolarFl) )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<p->binN; ++i)
|
||||||
|
{
|
||||||
|
p->magV[i] = std::abs(p->cplxV[i])/(p->inN/2);
|
||||||
|
p->phsV[i] = std::arg(p->cplxV[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// convert to rect
|
||||||
|
if( cwIsFlag(p->flags,kToRectFl) )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<p->binN; ++i)
|
||||||
|
{
|
||||||
|
p->magV[i] = std::real(p->cplxV[i]);
|
||||||
|
p->phsV[i] = std::imag(p->cplxV[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// do nothing - leave the result in p->cplxV[]
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
unsigned bin_count( ptr_str<T>* p ) { return p->binN; }
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
const T* magn( ptr_str<T>* p ) { return p->magV; }
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
const T* phase( ptr_str<T>* p ) { return p->phsV; }
|
||||||
|
|
||||||
|
rc_t test();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// IFFT
|
||||||
|
//
|
||||||
|
namespace ifft
|
||||||
|
{
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct ptr_str
|
||||||
|
{
|
||||||
|
T *outV;
|
||||||
|
std::complex<T> *cplxV;
|
||||||
|
|
||||||
|
unsigned outN;
|
||||||
|
unsigned binN;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
fftw_plan dplan;
|
||||||
|
fftwf_plan fplan;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct ptr_str<T>* create( unsigned binN )
|
||||||
|
{
|
||||||
|
struct ptr_str<T>* p = mem::allocZ< ptr_str<T> >(1);
|
||||||
|
|
||||||
|
p->binN = binN;
|
||||||
|
p->outN = (binN-1)*2;
|
||||||
|
|
||||||
|
if( std::is_same<T,float>::value )
|
||||||
|
{
|
||||||
|
p->outV = (T*)fftwf_malloc( sizeof(T)*p->outN );
|
||||||
|
p->cplxV = (std::complex<T>*)fftwf_malloc( sizeof(std::complex<T>)*p->outN);
|
||||||
|
p->u.fplan = fftwf_plan_dft_c2r_1d((int)p->outN, reinterpret_cast<fftwf_complex*>(p->cplxV), (float*)p->outV, FFTW_BACKWARD | FFTW_MEASURE );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->outV = (T*)fftw_malloc( sizeof(T)*p->outN );
|
||||||
|
p->cplxV = (std::complex<T>*)fftw_malloc( sizeof(std::complex<T>)*p->outN);
|
||||||
|
p->u.dplan = fftw_plan_dft_c2r_1d((int)p->outN, reinterpret_cast<fftw_complex*>(p->cplxV), (double*)p->outV, FFTW_BACKWARD | FFTW_MEASURE );
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
rc_t destroy( struct ptr_str<T>*& p )
|
||||||
|
{
|
||||||
|
if( p == nullptr )
|
||||||
|
return kOkRC;
|
||||||
|
|
||||||
|
if( std::is_same<T,float>::value )
|
||||||
|
{
|
||||||
|
fftwf_destroy_plan( p->u.fplan );
|
||||||
|
fftwf_free(p->outV);
|
||||||
|
fftwf_free(p->cplxV);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fftw_destroy_plan( p->u.dplan );
|
||||||
|
fftw_free(p->outV);
|
||||||
|
fftw_free(p->cplxV);
|
||||||
|
}
|
||||||
|
|
||||||
|
p->u.dplan = nullptr;
|
||||||
|
mem::release(p);
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
rc_t exec( struct ptr_str<T>* p, const T* magV, const T* phsV )
|
||||||
|
{
|
||||||
|
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
if( magV != nullptr && phsV != nullptr )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<p->binN; ++i)
|
||||||
|
p->cplxV[i] = std::polar( magV[i] / 2, phsV[i] );
|
||||||
|
|
||||||
|
for(unsigned i=p->outN-1,j=1; j<p->binN-1; --i,++j)
|
||||||
|
p->cplxV[i] = std::polar( magV[j] / 2, phsV[j] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( std::is_same<T,float>::value )
|
||||||
|
fftwf_execute(p->u.fplan);
|
||||||
|
else
|
||||||
|
fftw_execute(p->u.dplan);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
unsigned out_count( struct ptr_str<T>* p ) { return p->outN; }
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
const T* out( struct ptr_str<T>* p ) { return p->outV; }
|
||||||
|
|
||||||
|
|
||||||
|
rc_t test();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Convolution
|
||||||
|
//
|
||||||
|
namespace convolve
|
||||||
|
{
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct ptr_str
|
||||||
|
{
|
||||||
|
struct fft::ptr_str<T>* ft;
|
||||||
|
struct ifft::ptr_str<T>* ift;
|
||||||
|
|
||||||
|
std::complex<T>* hV;
|
||||||
|
unsigned hN;
|
||||||
|
|
||||||
|
T* olaV; // olaV[olaN]
|
||||||
|
unsigned olaN; // olaN == cN - procSmpN
|
||||||
|
T* outV; // outV[procSmpN]
|
||||||
|
unsigned outN; // outN == procSmpN
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
struct ptr_str<T>* create(const T* hV, unsigned hN, unsigned procSmpN, T hScale=1 )
|
||||||
|
{
|
||||||
|
struct ptr_str<T>* p = mem::allocZ<struct ptr_str<T>>(1);
|
||||||
|
|
||||||
|
unsigned cN = nextPowerOfTwo( hN + procSmpN - 1 );
|
||||||
|
|
||||||
|
p->ft = fft::create<T>(cN,0);
|
||||||
|
|
||||||
|
unsigned binN = fft::bin_count( p->ft );
|
||||||
|
|
||||||
|
p->ift = ifft::create<T>(binN);
|
||||||
|
p->hN = hN;
|
||||||
|
p->hV = mem::allocZ< std::complex<T> >(binN);
|
||||||
|
p->outV = mem::allocZ<T>( cN );
|
||||||
|
p->outN = procSmpN;
|
||||||
|
p->olaV = p->outV + procSmpN; // olaV[] overlaps outV[] with an offset of procSmpN
|
||||||
|
p->olaN = cN - procSmpN;
|
||||||
|
|
||||||
|
fft::exec( p->ft, hV, hN );
|
||||||
|
|
||||||
|
for(unsigned i=0; i<binN; ++i)
|
||||||
|
p->hV[i] = hScale * p->ft->cplxV[i] / ((T)cN);
|
||||||
|
|
||||||
|
printf("procN:%i cN:%i hN:%i binN:%i outN:%i\n", procSmpN, cN, hN, binN, p->outN );
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
rc_t destroy( struct ptr_str<T>*& pRef )
|
||||||
|
{
|
||||||
|
if( pRef == nullptr )
|
||||||
|
return kOkRC;
|
||||||
|
|
||||||
|
fft::destroy(pRef->ft);
|
||||||
|
ifft::destroy(pRef->ift);
|
||||||
|
mem::release(pRef->hV);
|
||||||
|
mem::release(pRef->outV);
|
||||||
|
mem::release(pRef);
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
rc_t exec( struct ptr_str<T>* p, const T* xV, unsigned xN )
|
||||||
|
{
|
||||||
|
// take FT of input signal
|
||||||
|
fft::exec( p->ft, xV, xN );
|
||||||
|
|
||||||
|
// multiply the signal spectra of the input signal and impulse response
|
||||||
|
for(unsigned i=0; i<p->ft->binN; ++i)
|
||||||
|
p->ift->cplxV[i] = p->hV[i] * p->ft->cplxV[i];
|
||||||
|
|
||||||
|
// take the IFFT of the convolved spectrum
|
||||||
|
ifft::exec<T>(p->ift,nullptr,nullptr);
|
||||||
|
|
||||||
|
// sum with previous impulse response tail
|
||||||
|
vop::add( p->outV, (const T*)p->olaV, (const T*)p->ift->outV, p->outN-1 );
|
||||||
|
|
||||||
|
// first sample of the impulse response tail is complete
|
||||||
|
p->outV[p->outN-1] = p->ift->outV[p->outN-1];
|
||||||
|
|
||||||
|
// store the new impulse response tail
|
||||||
|
vop::copy(p->olaV, p->ift->outV + p->outN, p->hN-1 );
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
rc_t apply( const T* xV, unsigned xN, const T* hV, unsigned hN, T* yV, unsigned yN, T hScale=1 )
|
||||||
|
{
|
||||||
|
unsigned procSmpN = std::min(xN,hN);
|
||||||
|
ptr_str<T> *p = create(hV,hN,procSmpN,hScale);
|
||||||
|
unsigned yi = 0;
|
||||||
|
|
||||||
|
//printf("procSmpN:%i\n",procSmpN);
|
||||||
|
|
||||||
|
for(unsigned xi=0; xi<xN && yi<yN; xi+=procSmpN )
|
||||||
|
{
|
||||||
|
exec<T>(p,xV+xi,std::min(procSmpN,xN-xi));
|
||||||
|
|
||||||
|
unsigned outN = std::min(yN-yi,p->outN);
|
||||||
|
vop::copy(yV+yi, p->outV, outN );
|
||||||
|
|
||||||
|
|
||||||
|
//printf("xi:%i yi:%i outN:%i\n", xi, yi, outN );
|
||||||
|
//vop::print( yV+yi, outN, "%f ", "outV ");
|
||||||
|
|
||||||
|
yi += outN;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("yi:%i\n",yi);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// if the tail of the hV[] is still in the OLA buffer
|
||||||
|
if( yi < yN )
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned outN = std::min(yN-yi, p->olaN);
|
||||||
|
|
||||||
|
// fill yV[] with as much of OLA as is available
|
||||||
|
vop::copy(yV + yi, p->olaV, outN);
|
||||||
|
yi += outN;
|
||||||
|
|
||||||
|
// zero any remaining space in yV[]
|
||||||
|
vop::zero(yV + yi, yN-yi );
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
destroy(p);
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t test();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -4,6 +4,7 @@
|
|||||||
#include "cwFileSys.h"
|
#include "cwFileSys.h"
|
||||||
#include "cwCommonImpl.h"
|
#include "cwCommonImpl.h"
|
||||||
#include "cwMem.h"
|
#include "cwMem.h"
|
||||||
|
#include "cwString.h"
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
#ifdef OS_LINUX
|
||||||
#include <libgen.h> // basename() dirname()
|
#include <libgen.h> // basename() dirname()
|
||||||
@ -242,16 +243,19 @@ char* cw::filesys::expandPath( const char* dir )
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( res.we_wordc > 1 )
|
switch( res.we_wordc )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kOpFailRC,"Unexpected word expansion count: %i.", res.we_wordc );
|
case 0:
|
||||||
goto errLabel;
|
newDir = str::dupl(dir);
|
||||||
}
|
break;
|
||||||
|
|
||||||
if( res.we_wordc == 1 )
|
case 1:
|
||||||
newDir = mem::duplStr(res.we_wordv[0]);
|
newDir = str::dupl(res.we_wordv[0]);
|
||||||
else
|
break;
|
||||||
newDir = mem::duplStr(dir);
|
|
||||||
|
default:
|
||||||
|
newDir = str::join(" ", (const char**)res.we_wordv, res.we_wordc );
|
||||||
|
}
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
if( rc != kOkRC )
|
if( rc != kOkRC )
|
||||||
|
19
cwObject.cpp
19
cwObject.cpp
@ -87,6 +87,17 @@ namespace cw
|
|||||||
|
|
||||||
rc_t _objTypeValueFromNonValue( const object_t* o, unsigned tid, void* dst )
|
rc_t _objTypeValueFromNonValue( const object_t* o, unsigned tid, void* dst )
|
||||||
{
|
{
|
||||||
|
switch(tid)
|
||||||
|
{
|
||||||
|
case kCStringTId:
|
||||||
|
*(const char**)dst = nullptr;
|
||||||
|
return kOkRC;
|
||||||
|
|
||||||
|
case kStringTId:
|
||||||
|
*(char**)dst = nullptr;
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
return cwLogError(kInvalidArgRC, "There is no conversion from '%s' to '%s'.", _objTypeIdToLabel(tid), o->type->label);
|
return cwLogError(kInvalidArgRC, "There is no conversion from '%s' to '%s'.", _objTypeIdToLabel(tid), o->type->label);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,6 +108,7 @@ namespace cw
|
|||||||
*(const char**)dst = o->u.str;
|
*(const char**)dst = o->u.str;
|
||||||
return kOkRC;
|
return kOkRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _objTypeValueFromNonValue(o,tid,dst);
|
return _objTypeValueFromNonValue(o,tid,dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +126,13 @@ namespace cw
|
|||||||
*(char**)dst = o->u.str;
|
*(char**)dst = o->u.str;
|
||||||
return kOkRC;
|
return kOkRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( tid == kNullTId )
|
||||||
|
{
|
||||||
|
*(char**)dst = nullptr;
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
return _objTypeValueFromNonValue(o,tid,dst);
|
return _objTypeValueFromNonValue(o,tid,dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
cwString.cpp
Normal file
47
cwString.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwMem.h"
|
||||||
|
#include "cwString.h"
|
||||||
|
|
||||||
|
|
||||||
|
unsigned cw::str::len( const char* s)
|
||||||
|
{
|
||||||
|
if( s == nullptr )
|
||||||
|
return 0;
|
||||||
|
return strlen(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* cw::str::dupl( const char* s )
|
||||||
|
{ return mem::duplStr(s); }
|
||||||
|
|
||||||
|
char* cw::str::join( const char* sep, const char** subStrArray, unsigned ssN )
|
||||||
|
{
|
||||||
|
unsigned sN = 0;
|
||||||
|
char* s = nullptr;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<ssN; ++i)
|
||||||
|
sN += len(subStrArray[i]);
|
||||||
|
|
||||||
|
if( ssN >= 1 )
|
||||||
|
sN += (ssN-1) * len(sep);
|
||||||
|
|
||||||
|
if( sN == 0 )
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
sN += 1;
|
||||||
|
|
||||||
|
s = mem::alloc<char>(sN);
|
||||||
|
|
||||||
|
s[0] = 0;
|
||||||
|
for(unsigned i=0; i<ssN; ++i)
|
||||||
|
{
|
||||||
|
strcat(s,subStrArray[i]);
|
||||||
|
if( sep != nullptr && ssN>=1 && i<ssN-1 )
|
||||||
|
strcat(s,sep);
|
||||||
|
|
||||||
|
assert( len(s) < sN );
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
16
cwString.h
Normal file
16
cwString.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef cwString_H
|
||||||
|
#define cwString_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace str
|
||||||
|
{
|
||||||
|
unsigned len( const char* s );
|
||||||
|
char* dupl( const char* s );
|
||||||
|
char* join( const char* sep, const char** subStrArray, unsigned ssN );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -121,3 +121,56 @@ void cw::doubleToX80(double val, unsigned char rate[10])
|
|||||||
*p++ = (u_char)(0xFF & (mant0));
|
*p++ = (u_char)(0xFF & (mant0));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool cw::isPowerOfTwo( unsigned x )
|
||||||
|
{
|
||||||
|
return !( (x < 2) || (x & (x-1)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned cw::nextPowerOfTwo( unsigned val )
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
unsigned mask = 1;
|
||||||
|
unsigned msb = 0;
|
||||||
|
unsigned cnt = 0;
|
||||||
|
|
||||||
|
// if val is a power of two return it
|
||||||
|
if( isPowerOfTwo(val) )
|
||||||
|
return val;
|
||||||
|
|
||||||
|
// next pow of zero is 2
|
||||||
|
if( val == 0 )
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
// if the next power of two can't be represented in 32 bits
|
||||||
|
if( val > 0x80000000)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find most sig. bit that is set - the number with only the next msb set is next pow 2
|
||||||
|
for(i=0; i<31; i++,mask<<=1)
|
||||||
|
if( mask & val )
|
||||||
|
{
|
||||||
|
msb = i;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1 << (msb + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned cw::nearestPowerOfTwo( unsigned i )
|
||||||
|
{
|
||||||
|
unsigned vh = nextPowerOfTwo(i);
|
||||||
|
|
||||||
|
if( vh == 2 )
|
||||||
|
return vh;
|
||||||
|
|
||||||
|
unsigned vl = vh / 2;
|
||||||
|
|
||||||
|
if( vh - i < i - vl )
|
||||||
|
return vh;
|
||||||
|
return vl;
|
||||||
|
}
|
||||||
|
@ -8,6 +8,11 @@ namespace cw
|
|||||||
double x80ToDouble( unsigned char s[10] );
|
double x80ToDouble( unsigned char s[10] );
|
||||||
void doubleToX80( double v, unsigned char s[10] );
|
void doubleToX80( double v, unsigned char s[10] );
|
||||||
|
|
||||||
|
bool isPowerOfTwo( unsigned x );
|
||||||
|
unsigned nextPowerOfTwo( unsigned val );
|
||||||
|
unsigned nearestPowerOfTwo( unsigned val );
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
32
cwVectOps.h
32
cwVectOps.h
@ -249,6 +249,38 @@ namespace cw
|
|||||||
y[i] = v;
|
y[i] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T seq( T* dbp, unsigned dn, const T& beg, const T& incr )
|
||||||
|
{
|
||||||
|
const T* dep = dbp + dn;
|
||||||
|
unsigned i = 0;
|
||||||
|
for(; dbp<dep; ++i)
|
||||||
|
*dbp++ = beg + (incr*i);
|
||||||
|
return beg + (incr*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
unsigned phasor( T* y, unsigned n, T srate, T hz, unsigned init_idx=0 )
|
||||||
|
{
|
||||||
|
for(unsigned i=init_idx; i<n; ++i)
|
||||||
|
y[i] = (M_PI*2*hz*i) / srate;
|
||||||
|
|
||||||
|
return init_idx + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
unsigned sine( T* y, unsigned n, T srate, T hz, unsigned init_idx=0 )
|
||||||
|
{
|
||||||
|
init_idx = phasor(y,n,srate,hz,init_idx);
|
||||||
|
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
y[i] = sin(y[i]);
|
||||||
|
|
||||||
|
return init_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user