From 62257d7d24c67cc486a22afc2dfa808ba29072d2 Mon Sep 17 00:00:00 2001 From: kevin Date: Tue, 22 Sep 2020 11:37:19 -0400 Subject: [PATCH] cwVectOps.h : Initial commit. cwTime.h: Added elaspsedMs() cwObject.h: Added getv_opt(). cwCommon.h: Added kInvalidStateRC Makefile: Added use of cwWEBSOCK build variable. cwAudioFileOps.h : Initial commit. cwAudioFile.h : Moved some operations so cwAudioFileOps.h cwCommonImpl.h : Removed is_int<> because has a std library implementation. --- Makefile.am | 28 +- cwAudioFile.cpp | 190 ------------ cwAudioFile.h | 9 +- cwAudioFileOps.cpp | 722 +++++++++++++++++++++++++++++++++++++++++++++ cwAudioFileOps.h | 52 ++++ cwCommon.h | 3 +- cwCommonImpl.h | 12 - cwObject.h | 36 ++- cwTime.cpp | 13 + cwTime.h | 2 + cwVectOps.h | 257 ++++++++++++++++ 11 files changed, 1091 insertions(+), 233 deletions(-) create mode 100644 cwAudioFileOps.cpp create mode 100644 cwAudioFileOps.h create mode 100644 cwVectOps.h diff --git a/Makefile.am b/Makefile.am index 5f203a1..07d281f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,12 +4,15 @@ libcwSRC = 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 -libcwHDR += src/libcw/cwMtx.h -libcwSRC += src/libcw/cwMtx.cpp +libcwHDR += src/libcw/cwVectOps.h src/libcw/cwMtx.h +libcwSRC += 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 libcwSRC += src/libcw/cwFileSys.cpp src/libcw/cwText.cpp src/libcw/cwFile.cpp src/libcw/cwTime.cpp src/libcw/cwLex.cpp +libcwHDR += src/libcw/cwLib.h +libcwSRC += src/libcw/cwLib.cpp + libcwHDR += src/libcw/cwObject.h src/libcw/cwObjectTemplate.h src/libcw/cwTextBuf.h libcwSRC += src/libcw/cwObject.cpp src/libcw/cwTextBuf.cpp @@ -19,15 +22,19 @@ 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 libcwSRC += src/libcw/cwSpScBuf.cpp src/libcw/cwSpScQueueTmpl.cpp -libcwHDR += src/libcw/cwSvg.h src/libcw/cwAudioFile.h -libcwSRC += src/libcw/cwSvg.cpp src/libcw/cwAudioFile.cpp +libcwHDR += src/libcw/cwSvg.h src/libcw/cwAudioFile.h src/libcw/cwAudioFileOps.h +libcwSRC += src/libcw/cwSvg.cpp src/libcw/cwAudioFile.cpp src/libcw/cwAudioFileOps.cpp -libcwHDR += src/libcw/cwWebSock.h src/libcw/cwWebSockSvr.h src/libcw/cwLib.h -libcwSRC += src/libcw/cwWebSock.cpp src/libcw/cwWebSockSvr.cpp src/libcw/cwLib.cpp +if cwWEBSOCK +libcwHDR += src/libcw/cwWebSock.h src/libcw/cwWebSockSvr.h +libcwSRC += src/libcw/cwWebSock.cpp src/libcw/cwWebSockSvr.cpp libcwHDR += src/libcw/cwUiDecls.h src/libcw/cwUi.h src/libcw/cwUiTest.h libcwSRC += src/libcw/cwUi.cpp src/libcw/cwUiTest.cpp +endif + + libcwHDR += src/libcw/cwSerialPortDecls.h src/libcw/cwSerialPort.h src/libcw/cwSerialPortSrv.h libcwSRC += src/libcw/cwSerialPort.cpp src/libcw/cwSerialPortSrv.cpp @@ -43,13 +50,14 @@ libcwSRC += src/libcw/cwAudioBuf.cpp libcwHDR += src/libcw/cwSocketDecls.h src/libcw/cwSocket.h libcwSRC += src/libcw/cwSocket.cpp -libcwHDR += src/libcw/cwIo.h src/libcw/cwIoTest.h -libcwSRC += src/libcw/cwIo.cpp src/libcw/cwIoTest.cpp - - 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 +if cwWEBSOCK +libcwHDR += src/libcw/cwIo.h src/libcw/cwIoTest.h +libcwSRC += src/libcw/cwIo.cpp src/libcw/cwIoTest.cpp +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 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 diff --git a/cwAudioFile.cpp b/cwAudioFile.cpp index c50d646..89aa770 100644 --- a/cwAudioFile.cpp +++ b/cwAudioFile.cpp @@ -1108,23 +1108,6 @@ namespace cw } - rc_t _testSine( const object_t* cfg ) - { - rc_t rc; - double srate, hz, gain, secs; - unsigned bits; - const char* fn = nullptr; - - if((rc = cfg->getv("fn",fn,"srate",srate,"bits",bits,"hz",hz,"gain",gain,"secs",secs)) != kOkRC ) - return cwLogError(kSyntaxErrorRC,"Invalid parameter to audio file sine test."); - - char* afn = filesys::expandPath(fn); - rc = sine( afn, srate, bits, hz, gain, secs ); - mem::release(afn); - - return rc; - } - rc_t _testReport( const object_t* cfg ) { rc_t rc = kOkRC; @@ -1725,176 +1708,6 @@ cw::rc_t cw::audiofile::setSrate( const char* fn, unsigned srate ) return rc; } -cw::rc_t cw::audiofile::sine( const char* fn, double srate, unsigned bits, double hz, double gain, double secs ) -{ - rc_t rc = kOkRC; - unsigned bN = srate * secs; - float* b = mem::alloc(bN); - unsigned chCnt = 1; - - unsigned i; - for(i=0; i maxActualFrmN ) - maxActualFrmN = actualFrmN; - - } - - // write the mixed output buffer - if((rc = writeFloat(oH, maxActualFrmN, maxChN, oChBuf )) != kOkRC ) - { - rc = cwLogError(kOpFailRC,"Write failed on output file '%s'.", outFn ); - goto errLabel; - } - } - } - - - errLabel: - if( rc != kOkRC ) - cwLogError(kOpFailRC,"Mix failed."); - - // close the source audio files - for(unsigned i=0; igetv("outFn",oFn,"outBits",outBits,"srcL",srcL)) != kOkRC ) - goto errLabel; - else - { - char* outFn = filesys::expandPath(oFn); - unsigned srcN = srcL->child_count(); - const char* fnV[ srcN ]; - float gainV[ srcN ]; - - memset(fnV,0,sizeof(fnV)); - - // read each source record - for(unsigned i=0; ichild_ele(i)->getv("gain",gainV[i],"src",fn)) != kOkRC ) - rc = cwLogError(kSyntaxErrorRC,"Mix source index %i syntax error."); - else - fnV[i] = filesys::expandPath(fn); - } - - if( rc == kOkRC ) - rc = mix( fnV, gainV, srcN, outFn, outBits); - - mem::free(outFn); - for(unsigned i=0; ifind("sine")) != nullptr ) - rc = _testSine(o); - if((o = cfg->find("rpt")) != nullptr ) rc = _testReport(o); diff --git a/cwAudioFile.h b/cwAudioFile.h index 911177a..ddddbfc 100644 --- a/cwAudioFile.h +++ b/cwAudioFile.h @@ -164,14 +164,7 @@ namespace cw // Change the sample rate value in the header. Note that this function does not resample the audio // signal it simply changes the value of the sample rate in the header. rc_t setSrate( const char* audioFn, unsigned srate ); - - // Generate a sine tone and write it to a file. - rc_t sine( const char* fn, double srate, unsigned bits, double hz, double gain, double secs ); - - // Mix a set of audio files. - rc_t mix( const char* fnV[], const float* gainV, unsigned srcN, const char* outFn, unsigned outBits ); - rc_t mix( const object_t* cfg ); - + // Testing and example routine for functions in .h. // Also see cmProcTest.c readWriteTest() rc_t test( const object_t* cfg ); diff --git a/cwAudioFileOps.cpp b/cwAudioFileOps.cpp new file mode 100644 index 0000000..da344ac --- /dev/null +++ b/cwAudioFileOps.cpp @@ -0,0 +1,722 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwMem.h" +#include "cwFile.h" +#include "cwObject.h" +#include "cwAudioFile.h" +#include "cwUtility.h" +#include "cwFileSys.h" +#include "cwAudioFileOps.h" + +cw::rc_t cw::afop::sine( const char* fn, double srate, unsigned bits, double hz, double gain, double secs ) +{ + rc_t rc = kOkRC; + unsigned bN = srate * secs; + float* b = mem::alloc(bN); + unsigned chCnt = 1; + + unsigned i; + for(i=0; igetv("fn",fn,"srate",srate,"bits",bits,"hz",hz,"gain",gain,"secs",secs)) != kOkRC ) + return cwLogError(kSyntaxErrorRC,"Invalid parameter to audio file sine test."); + + char* afn = filesys::expandPath(fn); + rc = sine( afn, srate, bits, hz, gain, secs ); + mem::release(afn); + + return rc; +} + +cw::rc_t cw::afop::mix( const char* fnV[], const float* gainV, unsigned srcN, const char* outFn, unsigned outBits ) +{ + rc_t rc = kOkRC; + + if( srcN == 0 ) + return rc; + + unsigned maxFrmN = 0; + unsigned maxChN = 0; + double srate = 0; + audiofile::handle_t hV[ srcN ]; + audiofile::handle_t oH; + + // open each source file and determine the output file audio format + for(unsigned i=0; i maxActualFrmN ) + maxActualFrmN = actualFrmN; + + } + + // write the mixed output buffer + if((rc = audiofile::writeFloat(oH, maxActualFrmN, maxChN, oChBuf )) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"Write failed on output file '%s'.", outFn ); + goto errLabel; + } + } + } + + errLabel: + if( rc != kOkRC ) + cwLogError(kOpFailRC,"Mix failed."); + + // close the source audio files + for(unsigned i=0; igetv("outFn",oFn,"outBits",outBits,"srcL",srcL)) != kOkRC ) + goto errLabel; + else + { + char* outFn = filesys::expandPath(oFn); + unsigned srcN = srcL->child_count(); + const char* fnV[ srcN ]; + float gainV[ srcN ]; + + memset(fnV,0,sizeof(fnV)); + + // read each source record + for(unsigned i=0; ichild_ele(i)->getv("gain",gainV[i],"src",fn)) != kOkRC ) + rc = cwLogError(kSyntaxErrorRC,"Mix source index %i syntax error."); + else + fnV[i] = filesys::expandPath(fn); + } + + if( rc == kOkRC ) + rc = mix( fnV, gainV, srcN, outFn, outBits); + + mem::free(outFn); + for(unsigned i=0; i= endSec ) + { + rc = cwLogError(kInvalidArgRC,"Invalid time selection. Begin time (%f) is greater than end time (%f). ", begSec, endSec ); + goto errLabel; + } + + // create the output file + if((rc = audiofile::create( oH, oFn, info.srate, outBits, info.chCnt)) != kOkRC ) + goto errLabel; + else + { + unsigned begFrmIdx = (unsigned)floor(begSec * info.srate); + unsigned endFrmIdx = endSec==-1 ? info.frameCnt : (unsigned)floor(endSec * info.srate); + unsigned ttlFrmN = endFrmIdx - begFrmIdx; + unsigned actualBufFrmN = 0; + const unsigned bufFrmN = 8196; // read/write buffer size + float buf[ bufFrmN*info.chCnt ]; + float* chBuf[ info.chCnt ]; + + // set up the read/write channel buffer + for(unsigned i = 0; i ttlFrmN ) + actualBufFrmN -= ttlFrmN - curFrmN; + + // write the buffer to the output file + if((rc = audiofile::writeFloat(oH, actualBufFrmN, info.chCnt, chBuf )) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"Write failed on output file '%s'.", oFn ); + goto errLabel; + } + + } + } + + errLabel: + if( rc != kOkRC ) + cwLogError(rc,"selectToFile failed."); + + audiofile::close(oH); + audiofile::close(iH); + mem::release(iFn); + mem::release(dstDir); + mem::release(oFn); + return rc; +} + +cw::rc_t cw::afop::selectToFile( const object_t* cfg ) +{ + rc_t rc = kOkRC; + const object_t* selectL = nullptr; + const char* oDir = nullptr; + unsigned outBits = 16; + + // read the top level cfg record + if((rc = cfg->getv("outDir",oDir,"outBits",outBits,"selectL",selectL)) != kOkRC ) + goto errLabel; + else + { + unsigned selN = selectL->child_count(); + + for(unsigned i=0; ichild_ele(i)->getv("begSec",begSec,"endSec",endSec,"dst",dstFn, "src",srcFn)) != kOkRC ) + { + rc = cwLogError(kSyntaxErrorRC,"'Select to file' index %i syntax error."); + goto errLabel; + } + + if((rc = selectToFile( srcFn, begSec, endSec, outBits, oDir, dstFn )) != kOkRC ) + goto errLabel; + + } + } + + errLabel: + return rc; +} + +namespace cw +{ + namespace afop + { + typedef struct _cutMixArg_str + { + const cutMixArg_t* arg; + char* srcFn; + unsigned srcFrmIdx; + unsigned srcFrmN; + unsigned srcFadeInFrmN; + unsigned srcFadeOutFrmN; + unsigned dstFrmIdx; + audiofile::handle_t afH; + audiofile::info_t afInfo; + } _cutMixArg_t; + + rc_t _cutAndMixOpen( const char* srcDir, const cutMixArg_t* argL, _cutMixArg_t* xArgL, unsigned argN, unsigned& chN_Ref, double& srate_Ref, unsigned& dstFrmN_Ref, unsigned& maxSrcFrmN_Ref ) + { + rc_t rc = kOkRC; + + maxSrcFrmN_Ref = 0; + chN_Ref = 0; + + for(unsigned i = 0; i argL[i].srcEndSec ) + { + rc = cwLogError(kInvalidArgRC,"The end time is prior to the begin time on source file '%s'.", xArgL[i].srcFn); + goto errLabel; + } + + xArgL[i].arg = argL + i; + xArgL[i].srcFrmIdx = floor(argL[i].srcBegSec * srate_Ref); + xArgL[i].srcFrmN = floor(argL[i].srcEndSec * srate_Ref) - xArgL[i].srcFrmIdx; + xArgL[i].srcFadeInFrmN = floor(argL[i].srcBegFadeSec * srate_Ref); + xArgL[i].srcFadeOutFrmN = floor(argL[i].srcEndFadeSec * srate_Ref); + xArgL[i].dstFrmIdx = floor(argL[i].dstBegSec * srate_Ref); + + chN_Ref = std::max( chN_Ref, xArgL[i].afInfo.chCnt ); + maxSrcFrmN_Ref = std::max( maxSrcFrmN_Ref, xArgL[i].srcFrmN ); + + dstFrmN_Ref = std::max( dstFrmN_Ref, xArgL[i].dstFrmIdx + xArgL[i].srcFrmN ); + + } + + errLabel: + return rc; + } + + rc_t _cutAndMixClose( _cutMixArg_t* xArgL, unsigned argN ) + { + rc_t rc = kOkRC; + + for(unsigned i = 0; i(dstFrmN*dstChN); // output signal buffer + srcV = mem::alloc(maxSrcFrmN*dstChN); // source signal buffer + + // create the src read buffer + for(unsigned i=0; igetv("dstFn",dstFn,"dstBits",dstBits,"srcDir",srcDir,"crossFadeSec",crossFadeSec,"argL",argNodeL)) != kOkRC ) + goto errLabel; + + if( argNodeL == nullptr ) + { + rc = cwLogError(kInvalidArgRC,"No crossfades were specified."); + } + else + { + unsigned argN = argNodeL->child_count(); + cutMixArg_t argL[ argN ]; + + printf("cm: %s %s %f\n",dstFn,srcDir,crossFadeSec); + + // for each source file + for(i=0; ichild_count(); ++i) + { + const object_t* o = argNodeL->child_ele(i); + + // parse the non-optional parameters + if((rc = o->getv("srcBegSec", argL[i].srcBegSec, "srcEndSec", argL[i].srcEndSec, "srcFn", argL[i].srcFn )) != kOkRC ) + { + rc = cwLogError(kInvalidArgRC,"Invalid crossfade argument at argument index %i.",i); + } + else + { + + 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].srcEndFadeSec = crossFadeSec; + + // parse the optional parameters + if((rc = o->getv_opt("dstBegSec", argL[i].dstBegSec, "srcBegFadeSec", argL[i].srcBegFadeSec, "srcEndFadeSec", argL[i].srcEndFadeSec )) != kOkRC ) + { + 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 ); + + } + + afSrcDir = filesys::expandPath(srcDir); + afDstFn = filesys::expandPath(dstFn); + + // call cross-fader + if((rc = cutAndMix( afDstFn, dstBits, afSrcDir, argL, argN )) != kOkRC ) + { + rc = cwLogError(rc,""); + goto errLabel; + } + + } + + errLabel: + mem::release(afSrcDir); + mem::release(afDstFn); + if( rc != kOkRC ) + rc = cwLogError(rc,"Cut and mix failed."); + return rc; +} + +cw::rc_t cw::afop::parallelMix( const char* dstFn, unsigned dstBits, const char* srcDir, const parallelMixArg_t* argL, unsigned argN ) +{ + cutMixArg_t cmArgL[ argN ]; + double fadeInSec = 0; + double dstBegSec = 0; + for(unsigned i=0; igetv("dstFn",dstFn,"dstBits",dstBits,"srcDir",srcDir,"argL",argNodeL)) != kOkRC ) + goto errLabel; + + if( argNodeL == nullptr ) + { + rc = cwLogError(kInvalidArgRC,"No crossfades were specified."); + } + else + { + unsigned argN = argNodeL->child_count(); + parallelMixArg_t argL[ argN ]; + + printf("%s %s\n",dstFn,srcDir); + + // for each source file + for(i=0; ichild_count(); ++i) + { + const object_t* o = argNodeL->child_ele(i); + + // 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 ) + { + rc = cwLogError(kInvalidArgRC,"Invalid crossfade argument at argument index %i.",i); + } + else + { + /* + // parse the optional parameters + if((rc = o->getv_opt("dstBegSec", argL[i].dstBegSec, "srcBegFadeSec", argL[i].srcBegFadeSec, "srcEndFadeSec", argL[i].srcEndFadeSec )) != kOkRC ) + { + rc = cwLogError(kInvalidArgRC,"Invalid crossfade optional argument at argument index %i.",i); + } + */ + } + + printf("beg:%f end:%f dst:%f %s\n", argL[i].srcBegSec, argL[i].srcEndSec, argL[i].fadeOutSec, argL[i].srcFn ); + + } + + afSrcDir = filesys::expandPath(srcDir); + afDstFn = filesys::expandPath(dstFn); + + // call cross-fader + if((rc = parallelMix( afDstFn, dstBits, afSrcDir, argL, argN )) != kOkRC ) + { + rc = cwLogError(rc,"Parallel mix failed."); + goto errLabel; + } + + } + + errLabel: + mem::release(afSrcDir); + mem::release(afDstFn); + if( rc != kOkRC ) + rc = cwLogError(rc,"Crossfade failed."); + return rc; +} + + +cw::rc_t cw::afop::test( const object_t* cfg ) +{ + rc_t rc = kOkRC; + const object_t* o; + + if((o = cfg->find("sine")) != nullptr ) + rc = sine(o); + + return rc; +} diff --git a/cwAudioFileOps.h b/cwAudioFileOps.h new file mode 100644 index 0000000..06c09b3 --- /dev/null +++ b/cwAudioFileOps.h @@ -0,0 +1,52 @@ +#ifndef cwAudioFileOps_h +#define cwAudioFileOps_h + +namespace cw +{ + namespace afop + { + + // Generate a sine tone and write it to a file. + rc_t sine( const char* fn, double srate, unsigned bits, double hz, double gain, double secs ); + rc_t sine( const object_t* cfg ); + + // Mix a set of audio files. + rc_t mix( const char* fnV[], const float* gainV, unsigned srcN, const char* outFn, unsigned outBits ); + rc_t mix( const object_t* cfg ); + + // Copy a time selection to an audio output file. + rc_t selectToFile( const char* srcFn, double begSec, double endSec, unsigned outBits, const char* outDir, const char* outFn ); + rc_t selectToFile( const object_t* cfg ); + + + // Cross fader + typedef struct { + const char* srcFn; // source audio file name + double srcBegSec; // source clip begin + double srcEndSec; // source clip end + 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 dstBegSec; // clip output location + } cutMixArg_t; + + rc_t cutAndMix( const char* outFn, unsigned outBits, const char* srcDir, const cutMixArg_t* argL, unsigned argN ); + rc_t cutAndMix( const object_t* cfg ); + + typedef struct + { + const char* srcFn; + double srcBegSec; + double srcEndSec; + double fadeOutSec; + } parallelMixArg_t; + + 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 test( const object_t* cfg ); + + } +} + + +#endif diff --git a/cwCommon.h b/cwCommon.h index 89ec2bc..e972be6 100644 --- a/cwCommon.h +++ b/cwCommon.h @@ -44,7 +44,8 @@ namespace cw kInvalidDataTypeRC, // 25 kFileNotFoundRC, // 26 kTestFailRC, // 27 - kBaseAppRC // 28 + kInvalidStateRC, // 28 + kBaseAppRC // 29 } cwRC_t; typedef unsigned rc_t; diff --git a/cwCommonImpl.h b/cwCommonImpl.h index 0dee861..ae78b3d 100644 --- a/cwCommonImpl.h +++ b/cwCommonImpl.h @@ -139,18 +139,6 @@ namespace cw - template< typename T> - bool is_int(const T& x) - { return false; } - - template<> inline bool is_int( const signed char& x ) { return true; } - template<> inline bool is_int( const unsigned char& x ) { return true; } - template<> inline bool is_int( const signed short& x ) { return true; } - template<> inline bool is_int( const unsigned short& x ) { return true; } - template<> inline bool is_int( const signed long& x ) { return true; } - template<> inline bool is_int( const unsigned long& x ) { return true; } - template<> inline bool is_int( const signed long long& x ) { return true; } - template<> inline bool is_int( const unsigned long long& x ) { return true; } diff --git a/cwObject.h b/cwObject.h index 66765e5..cfb5728 100644 --- a/cwObject.h +++ b/cwObject.h @@ -151,8 +151,8 @@ namespace cw const struct object_str* child_ele( unsigned idx ) const; struct object_str* child_ele( unsigned idx ); - // Set flag 'kNoRecurseFl' to no recurse into the object in search of the value. - // Set flag 'kOptional' if the label is optional and may not exist. + // Set flag 'kNoRecurseFl' to not recurse into the object in search of the value. + // Set flag 'kOptionalFl' if the label is optional and may not exist. template< typename T > rc_t get( const char* label, T& v, unsigned flags=0 ) const { @@ -168,21 +168,33 @@ namespace cw return o->value(v); } - rc_t getv() const { return kOkRC; } + rc_t _getv(unsigned flags) const { return kOkRC; } + + // getv("label0",v0,"label1",v1, ... ) + template< typename T0, typename T1, typename... ARGS > + rc_t _getv( unsigned flags, T0 label, T1& valRef, ARGS&&... args ) const + { + rc_t rc = get(label,valRef,flags); + + // if no error occurred .... + if( rc == kOkRC || (rc == kLabelNotFoundRC && cwIsFlag(flags,kOptionalFl))) + rc = _getv(flags, std::forward(args)...); // ... recurse + else + rc = cwLogError(rc,"object parse failed for the pair label:'%s'.",cwStringNullGuard(label)); + + return rc; + } // getv("label0",v0,"label1",v1, ... ) template< typename T0, typename T1, typename... ARGS > rc_t getv( T0 label, T1& valRef, ARGS&&... args ) const - { - rc_t rc; - - if((rc = get(label,valRef)) == kOkRC ) - if((rc = getv(std::forward(args)...)) != kOkRC ) - cwLogError(rc,"getv() failed for the pair label:'%s'.",cwStringNullGuard(label)); - - return rc; - } + { return _getv(0,label,valRef,args...); } + // getv("label0",v0,"label1",v1, ... ) where all values are optional + template< typename T0, typename T1, typename... ARGS > + rc_t getv_opt( T0 label, T1& valRef, ARGS&&... args ) const + { return _getv(kOptionalFl,label,valRef,args...); } + template< typename T > struct object_str* insertPair( const char* label, const T& v ) { return newPairObject(label, v, this); } diff --git a/cwTime.cpp b/cwTime.cpp index d6e756d..81a5dcb 100644 --- a/cwTime.cpp +++ b/cwTime.cpp @@ -61,9 +61,22 @@ unsigned cw::time::elapsedMicros( const spec_t& t0, const spec_t& t1 ) return u1 - u0; } +unsigned cw::time::elapsedMicros( const spec_t& t0 ) +{ + spec_t t1; + get(t1); + return elapsedMicros(t0,t1); +} + unsigned cw::time::elapsedMs( const spec_t& t0, const spec_t& t1 ) { return elapsedMicros(t0,t1)/1000; } +unsigned cw::time::elapsedMs( const spec_t& t0 ) +{ + spec_t t1; + get(t1); + return elapsedMs(t0,t1); +} unsigned cw::time::absElapsedMicros( const spec_t& t0, const spec_t& t1 ) { diff --git a/cwTime.h b/cwTime.h index d5b3c1c..34c485f 100644 --- a/cwTime.h +++ b/cwTime.h @@ -24,9 +24,11 @@ namespace cw // Return the elapsed time (t1 - t0) in microseconds // t1 is assumed to be at a later time than t0. unsigned elapsedMicros( const spec_t& t0, const spec_t& t1 ); + unsigned elapsedMicros( const spec_t& t0 ); // Wrapper on elapsedMicros() unsigned elapsedMs( const spec_t& t0, const spec_t& t1 ); + unsigned elapsedMs( const spec_t& t0 ); // Same as elapsedMicros() but the times are not assumed to be ordered. // The function therefore begins by swapping t1 and t0 if t0 is after t1. diff --git a/cwVectOps.h b/cwVectOps.h new file mode 100644 index 0000000..c132838 --- /dev/null +++ b/cwVectOps.h @@ -0,0 +1,257 @@ +#ifndef cwVectOps_h +#define cwVectOps_h + + +namespace cw +{ + namespace vop + { + template< typename T0 > + void print( const T0* v0, unsigned n, const char* fmt, const char* label=nullptr ) + { + if( label != nullptr ) + printf("%s : ",label); + + for(unsigned i=0; i + bool is_equal( const T0* v0, const T1* v1, unsigned n ) + { + for(unsigned i=0; i + void copy( T0* v0, const T1* v1, unsigned n ) + { + for(unsigned i=0; i + void fill( T0* v, unsigned n, const T1& value=0 ) + { + for(unsigned i=0; i + void zero( T* v, unsigned n ) + { fill(v,n,0); } + + + template< typename T > + unsigned arg_max( const T* v, unsigned n ) + { + if( n == 0 ) + return kInvalidIdx; + + unsigned mi = 0; + + for(unsigned i=1; i v[mi]) + mi = i; + + return mi; + } + + template< typename T > + unsigned arg_min( const T* v, unsigned n ) + { + if( n == 0 ) + return kInvalidIdx; + + unsigned mi = 0; + + for(unsigned i=1; i + const T max( const T* v, unsigned n ) + { + unsigned mi; + if((mi = arg_max(v,n)) == kInvalidIdx ) + return std::numeric_limits::max(); + return v[mi]; + } + + template< typename T > + const T min( const T* v, unsigned n ) + { + unsigned mi; + if((mi = arg_min(v,n)) == kInvalidIdx ) + return std::numeric_limits::max(); + return v[mi]; + } + + template< typename T0, typename T1 > + T0 mac( const T0* v0, const T1* v1, unsigned n ) + { + T0 acc = 0; + for(unsigned i=0; i + T cumsum( const T* v, unsigned n ) + { + T y = 0; + for(unsigned i=0; i + T cumprod( const T* v, unsigned n ) + { + T y = 1; + for(unsigned i=0; i + void mul( T0* v0, const T1* v1, unsigned n ) + { + for(unsigned i=0; i + void mul( T0* y0, const T0* v0, const T1* v1, unsigned n ) + { + for(unsigned i=0; i + void mul( T0* v0, const T1& scalar, unsigned n ) + { + for(unsigned i=0; i + void mul( T0* y0, const T0* v0, const T1& scalar, unsigned n ) + { + for(unsigned i=0; i + void add( T0* v0, const T1* v1, unsigned n ) + { + for(unsigned i=0; i + void add( T0* y0, const T0* v0, const T1* v1, unsigned n ) + { + for(unsigned i=0; i + void add( T0* v0, const T1& scalar, unsigned n ) + { + for(unsigned i=0; i + void add( T0* y0, const T0* v0, const T1& scalar, unsigned n ) + { + for(unsigned i=0; i + void div( T0* v0, const T1* v1, unsigned n ) + { + for(unsigned i=0; i + void div( T0* y0, const T0* v0, const T1* v1, unsigned n ) + { + for(unsigned i=0; i + void div( T0* v0, const T1& scalar, unsigned n ) + { + for(unsigned i=0; i + void div( T0* y0, const T0* v0, const T1& scalar, unsigned n ) + { + for(unsigned i=0; i + void sub( T0* v0, const T1* v1, unsigned n ) + { + for(unsigned i=0; i + void sub( T0* y0, const T0* v0, const T1* v1, unsigned n ) + { + for(unsigned i=0; i + void sub( T0* v0, const T1& scalar, unsigned n ) + { + for(unsigned i=0; i + void sub( T0* y0, const T0* v0, const T1& scalar, unsigned n ) + { + for(unsigned i=0; i + void seq( T* y, unsigned n, const T& beg, const T& cnt, const T& step=1 ) + { + if( cnt < n ) + n = cnt; + + T v = beg; + for(unsigned i=0; i