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.
This commit is contained in:
parent
fa33ac00c9
commit
62257d7d24
26
Makefile.am
26
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
|
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/cwMtx.h
|
libcwHDR += src/libcw/cwVectOps.h src/libcw/cwMtx.h
|
||||||
libcwSRC += src/libcw/cwMtx.cpp
|
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
|
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
|
||||||
|
|
||||||
|
libcwHDR += src/libcw/cwLib.h
|
||||||
|
libcwSRC += src/libcw/cwLib.cpp
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwObject.h src/libcw/cwObjectTemplate.h src/libcw/cwTextBuf.h
|
libcwHDR += src/libcw/cwObject.h src/libcw/cwObjectTemplate.h src/libcw/cwTextBuf.h
|
||||||
libcwSRC += src/libcw/cwObject.cpp src/libcw/cwTextBuf.cpp
|
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
|
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
|
libcwHDR += src/libcw/cwSvg.h src/libcw/cwAudioFile.h src/libcw/cwAudioFileOps.h
|
||||||
libcwSRC += src/libcw/cwSvg.cpp src/libcw/cwAudioFile.cpp
|
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
|
if cwWEBSOCK
|
||||||
libcwSRC += src/libcw/cwWebSock.cpp src/libcw/cwWebSockSvr.cpp src/libcw/cwLib.cpp
|
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
|
libcwHDR += src/libcw/cwUiDecls.h src/libcw/cwUi.h src/libcw/cwUiTest.h
|
||||||
libcwSRC += src/libcw/cwUi.cpp src/libcw/cwUiTest.cpp
|
libcwSRC += src/libcw/cwUi.cpp src/libcw/cwUiTest.cpp
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
libcwHDR += src/libcw/cwSerialPortDecls.h src/libcw/cwSerialPort.h src/libcw/cwSerialPortSrv.h
|
libcwHDR += src/libcw/cwSerialPortDecls.h src/libcw/cwSerialPort.h src/libcw/cwSerialPortSrv.h
|
||||||
libcwSRC += src/libcw/cwSerialPort.cpp src/libcw/cwSerialPortSrv.cpp
|
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
|
libcwHDR += src/libcw/cwSocketDecls.h src/libcw/cwSocket.h
|
||||||
libcwSRC += src/libcw/cwSocket.cpp
|
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
|
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
|
||||||
|
|
||||||
|
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
|
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
|
||||||
|
|
||||||
|
190
cwAudioFile.cpp
190
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 _testReport( const object_t* cfg )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -1725,176 +1708,6 @@ cw::rc_t cw::audiofile::setSrate( const char* fn, unsigned srate )
|
|||||||
return rc;
|
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<float>(bN);
|
|
||||||
unsigned chCnt = 1;
|
|
||||||
|
|
||||||
unsigned i;
|
|
||||||
for(i=0; i<bN; ++i)
|
|
||||||
b[i] = gain * sin(2.0*M_PI*hz*i/srate);
|
|
||||||
|
|
||||||
if((rc = writeFileFloat(fn, srate, bits, bN, chCnt, &b)) != kOkRC)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
cw::rc_t cw::audiofile::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;
|
|
||||||
handle_t hV[ srcN ];
|
|
||||||
handle_t oH;
|
|
||||||
|
|
||||||
// open each source file and determine the output file audio format
|
|
||||||
for(unsigned i=0; i<srcN; ++i)
|
|
||||||
{
|
|
||||||
info_t info;
|
|
||||||
|
|
||||||
if((rc = open( hV[i], fnV[i], &info )) != kOkRC )
|
|
||||||
{
|
|
||||||
rc = cwLogError(kOpFailRC,"Unable to open the audio mix source file '%s'.", fnV[i] );
|
|
||||||
goto errLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( srate == 0 )
|
|
||||||
srate = info.srate;
|
|
||||||
|
|
||||||
if( srate != info.srate )
|
|
||||||
{
|
|
||||||
rc = cwLogError(kInvalidArgRC,"The sample rate (%f) of '%s' does not match the sample rate (%f) of '%s'.", info.srate, fnV[i], srate, fnV[0] );
|
|
||||||
goto errLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( maxFrmN < info.frameCnt )
|
|
||||||
maxFrmN = info.frameCnt;
|
|
||||||
|
|
||||||
if( maxChN < info.chCnt )
|
|
||||||
maxChN = info.chCnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the output file
|
|
||||||
if((rc = create( oH, outFn, srate, outBits, maxChN)) != kOkRC )
|
|
||||||
goto errLabel;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const unsigned kBufFrmN = 1024;
|
|
||||||
float ibuf[ maxChN * kBufFrmN ];
|
|
||||||
float obuf[ maxChN * kBufFrmN ];
|
|
||||||
float* iChBuf[ maxChN ];
|
|
||||||
float* oChBuf[ maxChN ];
|
|
||||||
|
|
||||||
// setup the in/out channel buffers
|
|
||||||
for(unsigned i=0; i<maxChN; ++i)
|
|
||||||
{
|
|
||||||
iChBuf[i] = ibuf + (i*kBufFrmN);
|
|
||||||
oChBuf[i] = obuf + (i*kBufFrmN);
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each frame
|
|
||||||
for(unsigned frmIdx=0; frmIdx < maxFrmN; frmIdx += kBufFrmN )
|
|
||||||
{
|
|
||||||
// zero the mix buf
|
|
||||||
memset(obuf,0,sizeof(obuf));
|
|
||||||
|
|
||||||
unsigned maxActualFrmN = 0;
|
|
||||||
|
|
||||||
// for each source
|
|
||||||
for(unsigned i=0; i<srcN; ++i)
|
|
||||||
{
|
|
||||||
unsigned actualFrmN = 0;
|
|
||||||
|
|
||||||
// read a buffer of audio from the ith source.
|
|
||||||
if((rc = readFloat( hV[i], kBufFrmN, 0, channelCount(hV[i]), iChBuf, &actualFrmN)) != kOkRC )
|
|
||||||
{
|
|
||||||
rc = cwLogError(kOpFailRC,"Read failed on source '%s'.", name(hV[i]));
|
|
||||||
goto errLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// mix the input buffer into the output buffer
|
|
||||||
for(unsigned j=0; j<channelCount(hV[i]); ++j)
|
|
||||||
for(unsigned k=0; k<actualFrmN; ++k)
|
|
||||||
oChBuf[j][k] += gainV[i] * iChBuf[j][k];
|
|
||||||
|
|
||||||
// track the max. count of samples actually read for this buffer cycle
|
|
||||||
if( actualFrmN > 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; i<srcN; ++i)
|
|
||||||
close(hV[i]);
|
|
||||||
|
|
||||||
close(oH); // close the output file
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
cw::rc_t cw::audiofile::mix( const object_t* cfg )
|
|
||||||
{
|
|
||||||
rc_t rc = kOkRC;
|
|
||||||
const object_t* srcL = nullptr;
|
|
||||||
const char* oFn = nullptr;
|
|
||||||
unsigned outBits = 16;
|
|
||||||
|
|
||||||
// read the top level cfg record
|
|
||||||
if((rc = cfg->getv("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; i<srcN; ++i)
|
|
||||||
{
|
|
||||||
const char* fn = nullptr;
|
|
||||||
if((rc = srcL->child_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<srcN; ++i)
|
|
||||||
mem::free((char*)fnV[i]);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
errLabel:
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// [example]
|
/// [example]
|
||||||
@ -1905,9 +1718,6 @@ cw::rc_t cw::audiofile::test( const object_t* cfg )
|
|||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
const object_t* o;
|
const object_t* o;
|
||||||
|
|
||||||
if((o = cfg->find("sine")) != nullptr )
|
|
||||||
rc = _testSine(o);
|
|
||||||
|
|
||||||
if((o = cfg->find("rpt")) != nullptr )
|
if((o = cfg->find("rpt")) != nullptr )
|
||||||
rc = _testReport(o);
|
rc = _testReport(o);
|
||||||
|
|
||||||
|
@ -165,13 +165,6 @@ namespace cw
|
|||||||
// signal it simply changes the value of the sample rate in the header.
|
// signal it simply changes the value of the sample rate in the header.
|
||||||
rc_t setSrate( const char* audioFn, unsigned srate );
|
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.
|
// Testing and example routine for functions in .h.
|
||||||
// Also see cmProcTest.c readWriteTest()
|
// Also see cmProcTest.c readWriteTest()
|
||||||
rc_t test( const object_t* cfg );
|
rc_t test( const object_t* cfg );
|
||||||
|
722
cwAudioFileOps.cpp
Normal file
722
cwAudioFileOps.cpp
Normal file
@ -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<float>(bN);
|
||||||
|
unsigned chCnt = 1;
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
for(i=0; i<bN; ++i)
|
||||||
|
b[i] = gain * sin(2.0*M_PI*hz*i/srate);
|
||||||
|
|
||||||
|
if((rc = audiofile::writeFileFloat(fn, srate, bits, bN, chCnt, &b)) != kOkRC)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::afop::sine( 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<srcN; ++i)
|
||||||
|
{
|
||||||
|
audiofile::info_t info;
|
||||||
|
|
||||||
|
if((rc = audiofile::open( hV[i], fnV[i], &info )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Unable to open the audio mix source file '%s'.", fnV[i] );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( srate == 0 )
|
||||||
|
srate = info.srate;
|
||||||
|
|
||||||
|
if( srate != info.srate )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"The sample rate (%f) of '%s' does not match the sample rate (%f) of '%s'.", info.srate, fnV[i], srate, fnV[0] );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( maxFrmN < info.frameCnt )
|
||||||
|
maxFrmN = info.frameCnt;
|
||||||
|
|
||||||
|
if( maxChN < info.chCnt )
|
||||||
|
maxChN = info.chCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the output file
|
||||||
|
if((rc = audiofile::create( oH, outFn, srate, outBits, maxChN)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const unsigned kBufFrmN = 1024;
|
||||||
|
float ibuf[ maxChN * kBufFrmN ];
|
||||||
|
float obuf[ maxChN * kBufFrmN ];
|
||||||
|
float* iChBuf[ maxChN ];
|
||||||
|
float* oChBuf[ maxChN ];
|
||||||
|
|
||||||
|
// setup the in/out channel buffers
|
||||||
|
for(unsigned i=0; i<maxChN; ++i)
|
||||||
|
{
|
||||||
|
iChBuf[i] = ibuf + (i*kBufFrmN);
|
||||||
|
oChBuf[i] = obuf + (i*kBufFrmN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each frame
|
||||||
|
for(unsigned frmIdx=0; frmIdx < maxFrmN; frmIdx += kBufFrmN )
|
||||||
|
{
|
||||||
|
// zero the mix buf
|
||||||
|
memset(obuf,0,sizeof(obuf));
|
||||||
|
|
||||||
|
unsigned maxActualFrmN = 0;
|
||||||
|
|
||||||
|
// for each source
|
||||||
|
for(unsigned i=0; i<srcN; ++i)
|
||||||
|
{
|
||||||
|
unsigned actualFrmN = 0;
|
||||||
|
|
||||||
|
// read a buffer of audio from the ith source.
|
||||||
|
if((rc = audiofile::readFloat( hV[i], kBufFrmN, 0, channelCount(hV[i]), iChBuf, &actualFrmN)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Read failed on source '%s'.", name(hV[i]));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mix the input buffer into the output buffer
|
||||||
|
for(unsigned j=0; j<channelCount(hV[i]); ++j)
|
||||||
|
for(unsigned k=0; k<actualFrmN; ++k)
|
||||||
|
oChBuf[j][k] += gainV[i] * iChBuf[j][k];
|
||||||
|
|
||||||
|
// track the max. count of samples actually read for this buffer cycle
|
||||||
|
if( actualFrmN > 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; i<srcN; ++i)
|
||||||
|
audiofile::close(hV[i]);
|
||||||
|
|
||||||
|
audiofile::close(oH); // close the output file
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::afop::mix( const object_t* cfg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const object_t* srcL = nullptr;
|
||||||
|
const char* oFn = nullptr;
|
||||||
|
unsigned outBits = 16;
|
||||||
|
|
||||||
|
// read the top level cfg record
|
||||||
|
if((rc = cfg->getv("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; i<srcN; ++i)
|
||||||
|
{
|
||||||
|
const char* fn = nullptr;
|
||||||
|
if((rc = srcL->child_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<srcN; ++i)
|
||||||
|
mem::free((char*)fnV[i]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::afop::selectToFile( const char* srcFn, double begSec, double endSec, unsigned outBits, const char* outDir, const char* outFn )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
char* iFn = filesys::expandPath(srcFn);
|
||||||
|
char* dstDir = filesys::expandPath(outDir);
|
||||||
|
char* oFn = filesys::makeFn( dstDir, outFn, nullptr, nullptr );
|
||||||
|
audiofile::info_t info;
|
||||||
|
audiofile::handle_t iH;
|
||||||
|
audiofile::handle_t oH;
|
||||||
|
|
||||||
|
// open the source file
|
||||||
|
if((rc = audiofile::open( iH, iFn, &info )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
//
|
||||||
|
if( begSec >= 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<info.chCnt; ++i)
|
||||||
|
chBuf[i] = buf + i*bufFrmN;
|
||||||
|
|
||||||
|
// seek to first frame
|
||||||
|
if((rc = audiofile::seek(iH,begFrmIdx)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// for each read/write buffer in the selected region
|
||||||
|
for(unsigned curFrmN=0; curFrmN<ttlFrmN; curFrmN += actualBufFrmN )
|
||||||
|
{
|
||||||
|
|
||||||
|
// read a buffer of audio from the source.
|
||||||
|
if((rc = audiofile::readFloat( iH, bufFrmN, 0, info.chCnt, chBuf, &actualBufFrmN)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Read failed on source '%s'.", iFn );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this buffer would write more frames than the total frame count
|
||||||
|
// then decrease the count of samples in chBuf[]
|
||||||
|
if( curFrmN + actualBufFrmN > 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; i<selN; ++i)
|
||||||
|
{
|
||||||
|
double begSec = 0;
|
||||||
|
double endSec = -1;
|
||||||
|
const char* dstFn = nullptr;
|
||||||
|
const char* srcFn = nullptr;
|
||||||
|
|
||||||
|
if((rc = selectL->child_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<argN; ++i)
|
||||||
|
{
|
||||||
|
// create the source audio file name
|
||||||
|
xArgL[i].srcFn = filesys::makeFn(srcDir, argL[i].srcFn, NULL, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
// get the audio file info
|
||||||
|
if((rc = audiofile::open( xArgL[i].afH, xArgL[i].srcFn, &xArgL[i].afInfo )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc, "Unable to obtain info for the source audio file: '%s'.", cwStringNullGuard(xArgL[i].srcFn));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the system sample rate from the first file
|
||||||
|
if( i == 0 )
|
||||||
|
srate_Ref = xArgL[i].afInfo.srate;
|
||||||
|
|
||||||
|
// if the file sample rate does not match the system sample rate
|
||||||
|
if( srate_Ref != xArgL[i].afInfo.srate )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"'%s' sample rate %f does not match the system sample rate %f.", xArgL[i].srcFn, xArgL[i].afInfo.srate, srate_Ref );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify the source file begin/end time
|
||||||
|
if( argL[i].srcBegSec > 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<argN; ++i)
|
||||||
|
{
|
||||||
|
|
||||||
|
if((rc = audiofile::close( xArgL[i].afH )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"'%s' file closed.", xArgL[i].srcFn );
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mem::release( xArgL[i].srcFn );
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { kLinearFadeFl = 0x01, kEqualPowerFadeFl=0x02, kFadeInFl=0x04, kFadeOutFl=0x08 };
|
||||||
|
|
||||||
|
void _fadeOneChannel( float* xV, unsigned frmN, unsigned fadeFrmN, unsigned flags )
|
||||||
|
{
|
||||||
|
int i0,d,offs;
|
||||||
|
|
||||||
|
if( cwIsFlag(flags,kFadeInFl ) )
|
||||||
|
{
|
||||||
|
// count forward
|
||||||
|
i0 = 0;
|
||||||
|
d = 1;
|
||||||
|
offs = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// count backward
|
||||||
|
i0 = (int)fadeFrmN;
|
||||||
|
d = -1;
|
||||||
|
offs = frmN-fadeFrmN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do a linear fade
|
||||||
|
if( cwIsFlag(flags,kLinearFadeFl) )
|
||||||
|
{
|
||||||
|
for(int i = i0,j=0; j<(int)fadeFrmN; i+=d,++j )
|
||||||
|
{
|
||||||
|
assert(0 <= offs+j && offs+j < (int)frmN );
|
||||||
|
xV[offs+j] *= ((float)i) / fadeFrmN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // do an equal power fade
|
||||||
|
{
|
||||||
|
for(int i = i0,j=0; j<(int)fadeFrmN; i+=d,++j )
|
||||||
|
{
|
||||||
|
assert(0 <= offs+j && offs+j < (int)frmN );
|
||||||
|
xV[offs+j] *= std::sqrt(((float)i) / fadeFrmN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void _fadeAllChannels( float* chBufL[], unsigned chN, unsigned frmN, unsigned fadeFrmN, unsigned flags )
|
||||||
|
{
|
||||||
|
fadeFrmN = std::min(frmN,fadeFrmN);
|
||||||
|
|
||||||
|
for(unsigned i=0; i<chN; ++i)
|
||||||
|
_fadeOneChannel(chBufL[i],frmN,fadeFrmN,flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::afop::cutAndMix( const char* dstFn, unsigned dstBits, const char* srcDir, const cutMixArg_t* argL, unsigned argN )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned dstChN = 0;
|
||||||
|
double dstSrate = 0;
|
||||||
|
unsigned dstFrmN = 0;
|
||||||
|
unsigned maxSrcFrmN = 0;
|
||||||
|
float* dstV = nullptr;
|
||||||
|
float* srcV = nullptr;
|
||||||
|
_cutMixArg_t xArgL[ argN ];
|
||||||
|
|
||||||
|
// open each of the source files
|
||||||
|
if((rc = _cutAndMixOpen( srcDir, argL, xArgL, argN, dstChN, dstSrate, dstFrmN, maxSrcFrmN )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float* dstChBufL[ dstChN ];
|
||||||
|
float* srcChBufL[ dstChN ];
|
||||||
|
|
||||||
|
dstV = mem::allocZ<float>(dstFrmN*dstChN); // output signal buffer
|
||||||
|
srcV = mem::alloc<float>(maxSrcFrmN*dstChN); // source signal buffer
|
||||||
|
|
||||||
|
// create the src read buffer
|
||||||
|
for(unsigned i=0; i<dstChN; ++i)
|
||||||
|
{
|
||||||
|
dstChBufL[i] = dstV + (i*dstFrmN);
|
||||||
|
srcChBufL[i] = srcV + (i*maxSrcFrmN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each source file
|
||||||
|
for(unsigned i = 0; i<argN; ++i)
|
||||||
|
{
|
||||||
|
unsigned chIdx = 0;
|
||||||
|
unsigned actualFrmN = 0;
|
||||||
|
unsigned srcFrmN = xArgL[i].srcFrmN;
|
||||||
|
unsigned srcChN = xArgL[i].afInfo.chCnt;
|
||||||
|
|
||||||
|
// read the source segment
|
||||||
|
if((rc = audiofile::getFloat( xArgL[i].srcFn, xArgL[i].srcFrmIdx, srcFrmN, chIdx, srcChN, srcChBufL, &actualFrmN, nullptr)) != kOkRC )
|
||||||
|
{
|
||||||
|
cwLogError(rc,"Read source file '%s'.", xArgL[i].srcFn );
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
srcFrmN = std::min( srcFrmN, actualFrmN ); // Track the true size of the source buffer.
|
||||||
|
|
||||||
|
// Apply the fade in and out functions.
|
||||||
|
_fadeAllChannels(srcChBufL, srcChN, srcFrmN, xArgL[i].srcFadeInFrmN, kFadeInFl | kLinearFadeFl );
|
||||||
|
_fadeAllChannels(srcChBufL, srcChN, srcFrmN, xArgL[i].srcFadeOutFrmN, kFadeOutFl | kLinearFadeFl );
|
||||||
|
|
||||||
|
// sum into the source signal into the output buffer
|
||||||
|
for(unsigned j = 0; j<srcChN; ++j)
|
||||||
|
for(unsigned k = 0; k<srcFrmN; ++k)
|
||||||
|
{
|
||||||
|
assert( xArgL[i].dstFrmIdx + k < dstFrmN );
|
||||||
|
dstChBufL[j][ xArgL[i].dstFrmIdx + k ] += srcChBufL[j][k];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// write the output file
|
||||||
|
if((rc = audiofile::writeFileFloat( dstFn, dstSrate, dstBits, dstFrmN, dstChN, dstChBufL)) != kOkRC )
|
||||||
|
{
|
||||||
|
cwLogError(rc,"Output file ('%s') write failed.", cwStringNullGuard(dstFn));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
_cutAndMixClose( xArgL, argN );
|
||||||
|
|
||||||
|
mem::release(dstV);
|
||||||
|
mem::release(srcV);
|
||||||
|
if( rc != kOkRC )
|
||||||
|
cwLogError(rc,"Cross-fade failed.");
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::afop::cutAndMix( const object_t* cfg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const char* srcDir = nullptr;
|
||||||
|
const char* dstFn = nullptr;
|
||||||
|
unsigned dstBits = 16;
|
||||||
|
char* afSrcDir = nullptr;
|
||||||
|
char* afDstFn = nullptr;
|
||||||
|
double crossFadeSec = 0;
|
||||||
|
const object_t* argNodeL = nullptr;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
// read the top level cfg record
|
||||||
|
if((rc = cfg->getv("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; i<argNodeL->child_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; i<argN; ++i)
|
||||||
|
{
|
||||||
|
cmArgL[i].srcFn = argL[i].srcFn;
|
||||||
|
cmArgL[i].srcBegSec = argL[i].srcBegSec;
|
||||||
|
cmArgL[i].srcEndSec = argL[i].srcEndSec + argL[i].fadeOutSec;
|
||||||
|
cmArgL[i].srcBegFadeSec = fadeInSec;
|
||||||
|
cmArgL[i].srcEndFadeSec = argL[i].fadeOutSec;
|
||||||
|
cmArgL[i].dstBegSec = dstBegSec;
|
||||||
|
|
||||||
|
dstBegSec += argL[i].srcEndSec - argL[i].srcBegSec;
|
||||||
|
fadeInSec = argL[i].fadeOutSec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cutAndMix( dstFn, dstBits, srcDir, cmArgL, argN );
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::afop::parallelMix( const object_t* cfg )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const char* srcDir = nullptr;
|
||||||
|
const char* dstFn = nullptr;
|
||||||
|
unsigned dstBits = 16;
|
||||||
|
char* afSrcDir = nullptr;
|
||||||
|
char* afDstFn = nullptr;
|
||||||
|
const object_t* argNodeL = nullptr;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
printf("PARALLEL-MIX\n");
|
||||||
|
|
||||||
|
// read the top level cfg record
|
||||||
|
if((rc = cfg->getv("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; i<argNodeL->child_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;
|
||||||
|
}
|
52
cwAudioFileOps.h
Normal file
52
cwAudioFileOps.h
Normal file
@ -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
|
@ -44,7 +44,8 @@ namespace cw
|
|||||||
kInvalidDataTypeRC, // 25
|
kInvalidDataTypeRC, // 25
|
||||||
kFileNotFoundRC, // 26
|
kFileNotFoundRC, // 26
|
||||||
kTestFailRC, // 27
|
kTestFailRC, // 27
|
||||||
kBaseAppRC // 28
|
kInvalidStateRC, // 28
|
||||||
|
kBaseAppRC // 29
|
||||||
} cwRC_t;
|
} cwRC_t;
|
||||||
|
|
||||||
typedef unsigned rc_t;
|
typedef unsigned rc_t;
|
||||||
|
@ -139,18 +139,6 @@ namespace cw
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
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; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
34
cwObject.h
34
cwObject.h
@ -151,8 +151,8 @@ namespace cw
|
|||||||
const struct object_str* child_ele( unsigned idx ) const;
|
const struct object_str* child_ele( unsigned idx ) const;
|
||||||
struct object_str* child_ele( unsigned idx );
|
struct object_str* child_ele( unsigned idx );
|
||||||
|
|
||||||
// Set flag 'kNoRecurseFl' to no recurse into the object in search of the value.
|
// Set flag 'kNoRecurseFl' to not recurse into the object in search of the value.
|
||||||
// Set flag 'kOptional' if the label is optional and may not exist.
|
// Set flag 'kOptionalFl' if the label is optional and may not exist.
|
||||||
template< typename T >
|
template< typename T >
|
||||||
rc_t get( const char* label, T& v, unsigned flags=0 ) const
|
rc_t get( const char* label, T& v, unsigned flags=0 ) const
|
||||||
{
|
{
|
||||||
@ -168,20 +168,32 @@ namespace cw
|
|||||||
return o->value(v);
|
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>(args)...); // ... recurse
|
||||||
|
else
|
||||||
|
rc = cwLogError(rc,"object parse failed for the pair label:'%s'.",cwStringNullGuard(label));
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
// getv("label0",v0,"label1",v1, ... )
|
// getv("label0",v0,"label1",v1, ... )
|
||||||
template< typename T0, typename T1, typename... ARGS >
|
template< typename T0, typename T1, typename... ARGS >
|
||||||
rc_t getv( T0 label, T1& valRef, ARGS&&... args ) const
|
rc_t getv( T0 label, T1& valRef, ARGS&&... args ) const
|
||||||
{
|
{ return _getv(0,label,valRef,args...); }
|
||||||
rc_t rc;
|
|
||||||
|
|
||||||
if((rc = get(label,valRef)) == kOkRC )
|
// getv("label0",v0,"label1",v1, ... ) where all values are optional
|
||||||
if((rc = getv(std::forward<ARGS>(args)...)) != kOkRC )
|
template< typename T0, typename T1, typename... ARGS >
|
||||||
cwLogError(rc,"getv() failed for the pair label:'%s'.",cwStringNullGuard(label));
|
rc_t getv_opt( T0 label, T1& valRef, ARGS&&... args ) const
|
||||||
|
{ return _getv(kOptionalFl,label,valRef,args...); }
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
struct object_str* insertPair( const char* label, const T& v )
|
struct object_str* insertPair( const char* label, const T& v )
|
||||||
|
13
cwTime.cpp
13
cwTime.cpp
@ -61,9 +61,22 @@ unsigned cw::time::elapsedMicros( const spec_t& t0, const spec_t& t1 )
|
|||||||
return u1 - u0;
|
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 )
|
unsigned cw::time::elapsedMs( const spec_t& t0, const spec_t& t1 )
|
||||||
{ return elapsedMicros(t0,t1)/1000; }
|
{ 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 )
|
unsigned cw::time::absElapsedMicros( const spec_t& t0, const spec_t& t1 )
|
||||||
{
|
{
|
||||||
|
2
cwTime.h
2
cwTime.h
@ -24,9 +24,11 @@ namespace cw
|
|||||||
// Return the elapsed time (t1 - t0) in microseconds
|
// Return the elapsed time (t1 - t0) in microseconds
|
||||||
// t1 is assumed to be at a later time than t0.
|
// 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, const spec_t& t1 );
|
||||||
|
unsigned elapsedMicros( const spec_t& t0 );
|
||||||
|
|
||||||
// Wrapper on elapsedMicros()
|
// Wrapper on elapsedMicros()
|
||||||
unsigned elapsedMs( const spec_t& t0, const spec_t& t1 );
|
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.
|
// 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.
|
// The function therefore begins by swapping t1 and t0 if t0 is after t1.
|
||||||
|
257
cwVectOps.h
Normal file
257
cwVectOps.h
Normal file
@ -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<n; ++i)
|
||||||
|
printf(fmt,v0[i]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
bool is_equal( const T0* v0, const T1* v1, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
if( v0[i] != v1[i] )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void copy( T0* v0, const T1* v1, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
v0[i] = v1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void fill( T0* v, unsigned n, const T1& value=0 )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
v[i] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
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<n; ++i)
|
||||||
|
if( v[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<n; ++i)
|
||||||
|
if( v[i] < v[mi])
|
||||||
|
mi = i;
|
||||||
|
|
||||||
|
return mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
const T max( const T* v, unsigned n )
|
||||||
|
{
|
||||||
|
unsigned mi;
|
||||||
|
if((mi = arg_max(v,n)) == kInvalidIdx )
|
||||||
|
return std::numeric_limits<T>::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<T>::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<n; ++i)
|
||||||
|
acc += v0[i] * v1[i];
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T cumsum( const T* v, unsigned n )
|
||||||
|
{
|
||||||
|
T y = 0;
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
y += v[i];
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
T cumprod( const T* v, unsigned n )
|
||||||
|
{
|
||||||
|
T y = 1;
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
y *= v[i];
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void mul( T0* v0, const T1* v1, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
v0[i] *= v1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void mul( T0* y0, const T0* v0, const T1* v1, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
y0[i] = v0[i] * v1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void mul( T0* v0, const T1& scalar, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
v0[i] *= scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void mul( T0* y0, const T0* v0, const T1& scalar, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
y0[i] = v0[i] * scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void add( T0* v0, const T1* v1, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
v0[i] += v1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void add( T0* y0, const T0* v0, const T1* v1, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
y0[i] = v0[i] + v1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void add( T0* v0, const T1& scalar, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
v0[i] += scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void add( T0* y0, const T0* v0, const T1& scalar, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
y0[i] = v0[i] + scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void div( T0* v0, const T1* v1, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
v0[i] /= v1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void div( T0* y0, const T0* v0, const T1* v1, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
y0[i] = v0[i] / v1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void div( T0* v0, const T1& scalar, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
v0[i] /= scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void div( T0* y0, const T0* v0, const T1& scalar, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
y0[i] = v0[i] / scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void sub( T0* v0, const T1* v1, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
v0[i] -= v1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void sub( T0* y0, const T0* v0, const T1* v1, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
y0[i] = v0[i] / v1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void sub( T0* v0, const T1& scalar, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
v0[i] -= scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T0, typename T1 >
|
||||||
|
void sub( T0* y0, const T0* v0, const T1& scalar, unsigned n )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<n; ++i)
|
||||||
|
y0[i] = v0[i] / scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill y[0:min(n,cnt)] with values {beg,beg+step,beg+2*step .... beg+(cnt-1)*step}}
|
||||||
|
template< typename T >
|
||||||
|
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<n; ++i, v+=step)
|
||||||
|
y[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user