2014-01-25 21:13:42 +00:00
# include "cmGlobal.h"
2014-01-31 07:33:00 +00:00
# include "cmFloatTypes.h"
2014-01-25 21:13:42 +00:00
# include "cmRpt.h"
# include "cmErr.h"
# include "cmCtx.h"
# include "cmMem.h"
# include "cmMallocDebug.h"
# include "cmLinkedHeap.h"
# include "cmLex.h"
# include "cmCsv.h"
# include "cmSdb.h"
# include "cmText.h"
2014-01-31 07:33:00 +00:00
# include "cmMath.h"
# include "cmTime.h"
# include "cmMidi.h"
# include "cmVectOpsTemplateMain.h"
# include "cmAudioFile.h"
# include "cmFileSys.h"
2014-01-25 21:13:42 +00:00
typedef enum
{
kUuidColIdx ,
kBaseUuidColIdx ,
kChIdxColIdx ,
kObiColIdx ,
kIbiColIdx ,
kIeiColIdx ,
kOeiColIdx ,
kSrcColIdx ,
kMidiColIdx ,
kInstrColIdx ,
kSrateColIdx ,
kChCntColIdx ,
kNotesColIdx ,
kAfnColIdx ,
kInvalidColIdx
} cmSdbColIdx_t ;
struct cmSdb_str ;
2014-01-31 07:33:00 +00:00
typedef struct cmSdbSeqBlk_str
{
cmSdbSeqEvent_t * eV ;
unsigned cnt ;
struct cmSdbSeqBlk_str * link ;
} cmSdbSeqBlk_t ;
typedef struct cmSdbSeq_str
{
struct cmSdb_str * p ;
cmSdbSeqBlk_t * blocks ;
cmSdbSeqBlk_t * ebp ;
unsigned cnt ; // total count of events in all blocks
unsigned chCnt ; // max(chIdx)+1 of all events
double minDurSec ; // min dur of all events
double maxDurSec ; // max dur of all events
struct cmSdbSeq_str * link ;
} cmSdbSeq_t ;
2014-01-25 21:13:42 +00:00
typedef struct cmSdbRspBlk_str
{
unsigned * indexV ; // indexV[ cmSdb_t.blkIdxAllocCnt ]
unsigned cnt ; // count of indexes used
struct cmSdbRspBlk_str * link ; // cmSdbRsp_t.blocks link
} cmSdbRspBlk_t ;
typedef struct cmSdbRsp_str
{
struct cmSdb_str * p ; //
cmSdbRspBlk_t * blocks ; // first block ptr
cmSdbRspBlk_t * ebp ; // end block ptr
unsigned cnt ; // total count of indexes
struct cmSdbRsp_str * link ; // cmSdb_t.responses link
} cmSdbRsp_t ;
typedef struct cmSdb_str
{
2014-01-31 07:33:00 +00:00
cmCtx_t ctx ;
cmLHeapH_t lhH ;
cmCsvH_t csvH ;
cmSdbEvent_t * eV ;
unsigned eN ;
cmChar_t * audioDir ;
unsigned blkIdxAllocCnt ;
unsigned blkEvtAllocCnt ;
cmSdbRsp_t * responses ;
cmSdbSeq_t * seqs ;
2014-01-25 21:13:42 +00:00
} cmSdb_t ;
cmSdbH_t cmSdbNullHandle = cmSTATIC_NULL_HANDLE ;
cmSdbResponseH_t cmSdbResponseNullHandle = cmSTATIC_NULL_HANDLE ;
2014-01-31 07:33:00 +00:00
cmSdbSeqH_t cmSdbSeqNullHandle = cmSTATIC_NULL_HANDLE ;
2014-01-25 21:13:42 +00:00
cmSdb_t * _cmSdbHandleToPtr ( cmSdbH_t h )
{
cmSdb_t * p = ( cmSdb_t * ) h . h ;
assert ( p ! = NULL ) ;
return p ;
}
2014-01-31 07:33:00 +00:00
void _cmSdbRspFree ( cmSdbRsp_t * ) ;
cmSdbRC_t _cmSdbSeqFree ( cmSdbSeq_t * ) ;
2014-01-25 21:13:42 +00:00
cmSdbRC_t _cmSdbDestroy ( cmSdb_t * p )
{
cmSdbRC_t rc = kOkSdbRC ;
if ( cmCsvFinalize ( & p - > csvH ) ! = kOkCsvRC )
rc = cmErrMsg ( & p - > ctx . err , kCsvFailSdbRC , " CSV file finalize failed. " ) ;
while ( p - > responses ! = NULL )
2014-01-31 07:33:00 +00:00
_cmSdbRspFree ( p - > responses ) ;
while ( p - > seqs ! = NULL )
_cmSdbSeqFree ( p - > seqs ) ;
2014-01-25 21:13:42 +00:00
cmLHeapDestroy ( & p - > lhH ) ;
cmMemFree ( p ) ;
return rc ;
}
2014-01-31 07:33:00 +00:00
cmSdbRC_t cmSdbCreate ( cmCtx_t * ctx , cmSdbH_t * hp , const cmChar_t * csvFn , const cmChar_t * audioDir )
2014-01-25 21:13:42 +00:00
{
cmSdbRC_t rc ;
if ( ( rc = cmSdbDestroy ( hp ) ) ! = kOkSdbRC )
return rc ;
cmSdb_t * p = cmMemAllocZ ( cmSdb_t , 1 ) ;
p - > ctx = * ctx ;
2014-01-31 07:33:00 +00:00
p - > blkIdxAllocCnt = 1024 ;
p - > blkEvtAllocCnt = 1024 ;
2014-01-25 21:13:42 +00:00
cmErrSetup ( & p - > ctx . err , & ctx - > rpt , " sdb " ) ;
if ( cmLHeapIsValid ( p - > lhH = cmLHeapCreate ( 8192 , ctx ) ) = = false )
{
rc = cmErrMsg ( & p - > ctx . err , kLHeapFailSdbRC , " Linked heap mgr. allocation failed. " ) ;
goto errLabel ;
}
hp - > h = p ;
if ( csvFn ! = NULL )
2014-01-31 07:33:00 +00:00
if ( ( rc = cmSdbLoad ( * hp , csvFn , audioDir ) ) ! = kOkSdbRC )
2014-01-25 21:13:42 +00:00
goto errLabel ;
errLabel :
if ( rc ! = kOkSdbRC )
_cmSdbDestroy ( p ) ;
return rc ;
}
cmSdbRC_t cmSdbDestroy ( cmSdbH_t * hp )
{
cmSdbRC_t rc = kOkSdbRC ;
if ( hp = = NULL | | cmSdbIsValid ( * hp ) = = false )
return rc ;
cmSdb_t * p = _cmSdbHandleToPtr ( * hp ) ;
if ( ( rc = _cmSdbDestroy ( p ) ) ! = kOkSdbRC )
return rc ;
hp - > h = NULL ;
return rc ;
}
bool cmSdbIsValid ( cmSdbH_t h )
{ return h . h ! = NULL ; }
cmSdbRC_t _cmSdbSyntaxError ( cmSdb_t * p , const cmChar_t * csvFn , unsigned rowIdx , unsigned colIdx , const cmChar_t * colLabel )
{
return cmErrMsg ( & p - > ctx . err , kSyntaxErrSdbRC , " A syntax error was found at row %i col %i (label:%s) in ' % s ' . " ,rowIdx+1,colIdx+1,cmStringNullGuard(colLabel),cmStringNullGuard(csvFn)) ;
}
2014-01-31 07:33:00 +00:00
cmSdbRC_t cmSdbLoad ( cmSdbH_t h , const cmChar_t * csvFn , const cmChar_t * audioDir )
2014-01-25 21:13:42 +00:00
{
cmSdbRC_t rc = kOkSdbRC ;
unsigned i ;
cmSdb_t * p = _cmSdbHandleToPtr ( h ) ;
if ( cmCsvInitializeFromFile ( & p - > csvH , csvFn , 0 , & p - > ctx ) ! = kOkCsvRC )
{
rc = cmErrMsg ( & p - > ctx . err , kCsvFailSdbRC , " CSV file load fail on '%s'. " , cmStringNullGuard ( csvFn ) ) ;
goto errLabel ;
}
p - > eN = cmCsvRowCount ( p - > csvH ) - 1 ;
// release all the memory held by the linked heap
cmLHeapClear ( p - > lhH , true ) ;
p - > eV = cmLhAllocZ ( p - > lhH , cmSdbEvent_t , p - > eN ) ;
2014-01-31 07:33:00 +00:00
2014-01-25 21:13:42 +00:00
for ( i = 0 ; rc = = kOkSdbRC & & i < p - > eN ; + + i )
{
unsigned rowIdx = i + 1 ;
if ( ( p - > eV [ i ] . uuid = cmCsvCellUInt ( p - > csvH , rowIdx , kUuidColIdx ) ) = = UINT_MAX )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kUuidColIdx , " uuid " ) ;
if ( ( p - > eV [ i ] . baseUuid = cmCsvCellUInt ( p - > csvH , rowIdx , kBaseUuidColIdx ) ) = = UINT_MAX )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kBaseUuidColIdx , " baseUuid " ) ;
if ( ( p - > eV [ i ] . chIdx = cmCsvCellUInt ( p - > csvH , rowIdx , kChIdxColIdx ) ) = = UINT_MAX )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kChIdxColIdx , " chIdx " ) ;
else
p - > eV [ i ] . chIdx - = 1 ; // CSV channel index is 1 based
if ( ( p - > eV [ i ] . obi = cmCsvCellUInt ( p - > csvH , rowIdx , kObiColIdx ) ) = = UINT_MAX )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kObiColIdx , " obi " ) ;
else
p - > eV [ i ] . obi - = 1 ;
if ( ( p - > eV [ i ] . ibi = cmCsvCellUInt ( p - > csvH , rowIdx , kIbiColIdx ) ) = = UINT_MAX )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kIbiColIdx , " ibi " ) ;
else
p - > eV [ i ] . ibi - = 1 ;
if ( ( p - > eV [ i ] . iei = cmCsvCellUInt ( p - > csvH , rowIdx , kIeiColIdx ) ) = = UINT_MAX )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kIeiColIdx , " obi " ) ;
else
p - > eV [ i ] . iei - = 1 ;
if ( ( p - > eV [ i ] . oei = cmCsvCellUInt ( p - > csvH , rowIdx , kOeiColIdx ) ) = = UINT_MAX )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kOeiColIdx , " ibi " ) ;
else
p - > eV [ i ] . oei - = 1 ;
if ( ( p - > eV [ i ] . src = cmCsvCellText ( p - > csvH , rowIdx , kSrcColIdx ) ) = = NULL )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kSrcColIdx , " src " ) ;
if ( ( p - > eV [ i ] . midi = cmCsvCellInt ( p - > csvH , rowIdx , kMidiColIdx ) ) = = INT_MAX )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kMidiColIdx , " midi " ) ;
if ( ( p - > eV [ i ] . instr = cmCsvCellText ( p - > csvH , rowIdx , kInstrColIdx ) ) = = NULL )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kInstrColIdx , " instr " ) ;
if ( ( p - > eV [ i ] . srate = cmCsvCellUInt ( p - > csvH , rowIdx , kSrateColIdx ) ) = = UINT_MAX )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kSrateColIdx , " srate " ) ;
if ( ( p - > eV [ i ] . chCnt = cmCsvCellUInt ( p - > csvH , rowIdx , kChCntColIdx ) ) = = UINT_MAX )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kChCntColIdx , " chCnt " ) ;
cmCsvCell_t * c ;
if ( ( c = cmCsvCellPtr ( p - > csvH , rowIdx , kNotesColIdx ) ) = = NULL )
{
rc = cmErrMsg ( & p - > ctx . err , kSyntaxErrSdbRC , " Syntax Error: No 'notes' or 'audio file name' field for row %i in '%s'. " , rowIdx + 1 , cmStringNullGuard ( csvFn ) ) ;
goto errLabel ;
}
// count the number of 'notes'
unsigned nn = 0 ;
for ( ; c - > rowPtr ! = NULL ; c = c - > rowPtr )
+ + nn ;
if ( nn > 0 )
{
unsigned k = 0 ;
// allocate the 'notes' ptr array - the last entry is set to NULL.
p - > eV [ i ] . notesV = cmLhAllocZ ( p - > lhH , const cmChar_t * , nn + 1 ) ;
// read each note
for ( c = cmCsvCellPtr ( p - > csvH , rowIdx , kNotesColIdx ) ; c ! = NULL & & c - > rowPtr ! = NULL ; c = c - > rowPtr , + + k )
if ( ( p - > eV [ i ] . notesV [ k ] = cmCsvCellText ( p - > csvH , rowIdx , kNotesColIdx + k ) ) = = NULL )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kNotesColIdx + k , " notes " ) ;
assert ( k = = nn ) ;
}
// read the audio file name
if ( ( p - > eV [ i ] . afn = cmCsvCellText ( p - > csvH , rowIdx , kNotesColIdx + nn ) ) = = NULL )
rc = _cmSdbSyntaxError ( p , csvFn , rowIdx , kNotesColIdx + nn , " afn " ) ;
}
2014-01-31 07:33:00 +00:00
// store the audio directory
if ( cmTextLength ( audioDir ) )
p - > audioDir = cmLhAllocStr ( p - > lhH , audioDir ) ;
else
{
cmLhFree ( p - > lhH , & p - > audioDir ) ;
p - > audioDir = NULL ;
}
2014-01-25 21:13:42 +00:00
errLabel :
return rc ;
}
2014-01-31 07:33:00 +00:00
cmSdbRC_t cmSdbSyncChPairs ( cmSdbH_t h )
{
cmSdbRC_t rc = kOkSdbRC ;
cmSdb_t * p = _cmSdbHandleToPtr ( h ) ;
unsigned i ;
// for each multi-channel event
for ( i = 0 ; i < p - > eN ; + + i )
if ( p - > eV [ i ] . chCnt > 1 )
{
const cmSdbEvent_t * ep = p - > eV + i ;
unsigned iV [ ep - > chCnt ] ;
unsigned j , k ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
// load iV[] with the event indexes of the channel pairs
for ( j = 0 , k = 0 ; j < p - > eN & & k < ep - > chCnt ; + + j )
if ( p - > eV [ j ] . baseUuid = = ep - > baseUuid )
{
assert ( p - > eV [ j ] . chIdx < ep - > chCnt ) ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
iV [ p - > eV [ j ] . chIdx ] = j ;
+ + k ;
}
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
if ( k ! = ep - > chCnt )
rc = cmErrMsg ( & p - > ctx . err , kChPairNotFoundSdbRC , " The channel pair associated with 'id:%i instr:%s src:%s ch index:%i could not be found. " , ep - > uuid , cmStringNullGuard ( ep - > instr ) , cmStringNullGuard ( ep - > src ) , ep - > chIdx ) ;
else
{
unsigned mobi = ep - > obi ;
unsigned mibi = ep - > ibi ;
unsigned miei = ep - > iei ;
unsigned moei = ep - > oei ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
// get the min onsets and max offsets
for ( j = 0 ; j < ep - > chCnt ; + + j )
{
mobi = cmMin ( mobi , p - > eV [ iV [ j ] ] . obi ) ;
mibi = cmMin ( mibi , p - > eV [ iV [ j ] ] . ibi ) ;
miei = cmMax ( miei , p - > eV [ iV [ j ] ] . iei ) ;
moei = cmMax ( moei , p - > eV [ iV [ j ] ] . oei ) ;
}
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
// set the onsets to the min onset / offsets to max offsets
for ( j = 0 ; j < ep - > chCnt ; + + j )
{
p - > eV [ iV [ j ] ] . obi = mobi ;
p - > eV [ iV [ j ] ] . ibi = mibi ;
p - > eV [ iV [ j ] ] . iei = miei ;
p - > eV [ iV [ j ] ] . oei = moei ;
}
}
}
return rc ;
2014-01-25 21:13:42 +00:00
}
2014-01-31 07:33:00 +00:00
const cmSdbEvent_t * _cmSdbEvent ( cmSdb_t * p , unsigned uuid )
2014-01-25 21:13:42 +00:00
{
2014-01-31 07:33:00 +00:00
unsigned i ;
for ( i = 0 ; i < p - > eN ; + + i )
if ( p - > eV [ i ] . uuid = = uuid )
return p - > eV + i ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
return NULL ;
}
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
const cmSdbEvent_t * cmSdbEvent ( cmSdbH_t h , unsigned uuid )
{
cmSdb_t * p = _cmSdbHandleToPtr ( h ) ;
return _cmSdbEvent ( p , uuid ) ;
2014-01-25 21:13:42 +00:00
}
2014-01-31 07:33:00 +00:00
//================================================================================================================================
cmSdbRsp_t * _cmSdbRspHandleToPtr ( cmSdbResponseH_t h )
2014-01-25 21:13:42 +00:00
{
2014-01-31 07:33:00 +00:00
cmSdbRsp_t * p = ( cmSdbRsp_t * ) h . h ;
assert ( p ! = NULL ) ;
return p ;
}
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
void _cmSdbRspBlkFree ( cmSdb_t * p , cmSdbRspBlk_t * bp )
{
cmLhFree ( p - > lhH , bp - > indexV ) ;
cmLhFree ( p - > lhH , bp ) ;
}
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
cmSdbRspBlk_t * _cmSdbRspBlkUnlink ( cmSdbRsp_t * rp , cmSdbRspBlk_t * bp )
{
cmSdbRspBlk_t * dp = rp - > blocks ;
cmSdbRspBlk_t * pp = NULL ;
for ( ; dp ! = NULL ; dp = dp - > link )
{
if ( dp = = bp )
2014-01-25 21:13:42 +00:00
{
2014-01-31 07:33:00 +00:00
if ( pp = = NULL )
rp - > blocks = dp - > link ;
else
pp - > link = dp - > link ;
return bp ;
2014-01-25 21:13:42 +00:00
}
2014-01-31 07:33:00 +00:00
pp = dp ;
}
assert ( 0 ) ;
return NULL ;
}
void _cmSdbRspInsertIndex ( cmSdb_t * p , cmSdbRsp_t * rp , unsigned evtIndex )
{
if ( rp - > ebp = = NULL | | rp - > ebp - > cnt = = p - > blkIdxAllocCnt )
{
cmSdbRspBlk_t * bp = cmLhAllocZ ( p - > lhH , cmSdbRspBlk_t , 1 ) ;
bp - > indexV = cmLhAllocZ ( p - > lhH , unsigned , p - > blkIdxAllocCnt ) ;
if ( rp - > ebp ! = NULL )
rp - > ebp - > link = bp ;
if ( rp - > blocks = = NULL )
rp - > blocks = bp ;
rp - > ebp = bp ;
}
assert ( rp - > ebp ! = NULL & & rp - > ebp - > cnt < p - > blkIdxAllocCnt ) ;
rp - > ebp - > indexV [ rp - > ebp - > cnt + + ] = evtIndex ;
rp - > cnt + = 1 ;
}
cmSdbRsp_t * _cmSdbRspUnlink ( cmSdbRsp_t * rp )
{
cmSdb_t * p = rp - > p ;
cmSdbRsp_t * dp = p - > responses ;
cmSdbRsp_t * pp = NULL ;
for ( ; dp ! = NULL ; dp = dp - > link )
{
if ( dp = = rp )
{
if ( pp = = NULL )
p - > responses = dp - > link ;
else
pp - > link = dp - > link ;
return rp ;
}
pp = dp ;
}
assert ( 0 ) ;
return NULL ;
}
void _cmSdbRspFree ( cmSdbRsp_t * rp )
{
_cmSdbRspUnlink ( rp ) ;
while ( rp - > blocks ! = NULL )
{
cmSdbRspBlk_t * np = rp - > blocks - > link ;
cmSdbRspBlk_t * bp ;
if ( ( bp = _cmSdbRspBlkUnlink ( rp , rp - > blocks ) ) ! = NULL )
_cmSdbRspBlkFree ( rp - > p , bp ) ;
rp - > blocks = np ;
}
cmLhFree ( rp - > p - > lhH , rp ) ;
}
cmSdbRsp_t * _cmSdbRspAlloc ( cmSdb_t * p )
{
cmSdbRsp_t * rp = cmLhAllocZ ( p - > lhH , cmSdbRsp_t , 1 ) ;
rp - > p = p ;
rp - > link = p - > responses ;
p - > responses = rp ;
return rp ;
}
// Compare 'label' to every string in tV[i] and return true if any comparision is a match.
// If 'subFlV[i]' is set then 'label' must only contain tV[i] as a substring to match.
// If 'negFlV[i]' is set then return true if any comparision is a mismatch.
bool _cmSdbSelectText ( const cmSdbEvent_t * r , const cmChar_t * * tV , const bool * subFlV , const bool * negFlV , const cmChar_t * label )
{
unsigned i ;
if ( label = = NULL )
return false ;
if ( tV = = NULL )
return true ;
for ( i = 0 ; tV [ i ] ! = NULL ; + + i )
{
bool matchFl = false ;
if ( subFlV [ i ] )
matchFl = strstr ( label , tV [ i ] ) ! = NULL ;
else
matchFl = strcmp ( tV [ i ] , label ) = = 0 ;
if ( negFlV [ i ] )
matchFl = ! matchFl ;
if ( matchFl )
return true ;
}
return false ;
}
unsigned _cmSdbStrVectCnt ( const cmChar_t * * v )
{
unsigned n = 0 ;
unsigned i = 0 ;
if ( v = = NULL )
return 0 ;
for ( i = 0 ; v [ i ] ! = NULL ; + + i )
+ + n ;
return n ;
}
void _cmSdbStrVectFlags ( const cmChar_t * * v , bool * sV , bool * nV )
{
unsigned i = 0 ;
if ( v = = NULL )
return ;
for ( i = 0 ; v [ i ] ! = NULL ; + + i )
{
nV [ i ] = false ;
sV [ i ] = false ;
if ( strncmp ( v [ i ] , " *! " , 2 ) = = 0 | | strncmp ( v [ i ] , " !* " , 2 ) = = 0 )
{
sV [ i ] = nV [ i ] = true ;
v [ i ] + = 2 ;
}
else
{
if ( strncmp ( v [ i ] , " ! " , 1 ) = = 0 )
{
nV [ i ] = true ;
v [ i ] + = 1 ;
}
if ( strncmp ( v [ i ] , " * " , 1 ) = = 0 )
2014-01-25 21:13:42 +00:00
{
sV [ i ] = true ;
v [ i ] + = 1 ;
}
}
}
}
cmSdbRC_t cmSdbSelect (
cmSdbH_t h ,
double srate ,
const cmChar_t * * instrV ,
const cmChar_t * * srcV ,
const cmChar_t * * notesV ,
2014-01-31 07:33:00 +00:00
const unsigned * pitchV ,
2014-01-25 21:13:42 +00:00
double minDurSec ,
double maxDurSec ,
unsigned minChCnt ,
cmSdbResponseH_t * rhp )
{
2014-01-31 07:33:00 +00:00
cmSdbRC_t rc ;
if ( ( rc = cmSdbResponseFree ( rhp ) ) ! = kOkSdbRC )
return rc ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
cmSdb_t * p = _cmSdbHandleToPtr ( h ) ;
cmSdbRsp_t * rp = _cmSdbRspAlloc ( p ) ;
unsigned i ;
2014-01-25 21:13:42 +00:00
// get the length of each string vector
unsigned srcN = _cmSdbStrVectCnt ( srcV ) ;
unsigned insN = _cmSdbStrVectCnt ( instrV ) ;
unsigned notN = _cmSdbStrVectCnt ( notesV ) ;
// allocate flag vectors
bool srcSubFlV [ srcN ] ;
bool srcNegFlV [ srcN ] ;
bool insSubFlV [ insN ] ;
bool insNegFlV [ insN ] ;
bool notSubFlV [ notN ] ;
bool notNegFlV [ notN ] ;
// fill the flag vectors
_cmSdbStrVectFlags ( srcV , srcSubFlV , srcNegFlV ) ;
_cmSdbStrVectFlags ( instrV , insSubFlV , insNegFlV ) ;
_cmSdbStrVectFlags ( notesV , notSubFlV , notNegFlV ) ;
for ( i = 0 ; i < p - > eN ; + + i )
{
const cmSdbEvent_t * r = p - > eV + i ;
double durSec = ( double ) r - > srate * ( r - > oei - r - > obi ) ;
unsigned j ;
if ( srate ! = 0 & & srate ! = r - > srate )
continue ;
if ( durSec < minDurSec | | ( maxDurSec ! = 0 & & maxDurSec < durSec ) )
continue ;
if ( minChCnt ! = 0 & & r - > chCnt > minChCnt )
continue ;
if ( ! _cmSdbSelectText ( r , srcV , srcSubFlV , srcNegFlV , r - > src ) )
continue ;
if ( ! _cmSdbSelectText ( r , instrV , insSubFlV , insNegFlV , r - > instr ) )
continue ;
2014-01-31 07:33:00 +00:00
if ( pitchV ! = NULL )
{
for ( j = 0 ; pitchV [ j ] ! = kInvalidMidiPitch ; + + j )
if ( pitchV [ j ] = = r - > midi )
break ;
if ( pitchV [ j ] ! = r - > midi )
continue ;
}
2014-01-25 21:13:42 +00:00
if ( r - > notesV ! = NULL )
2014-01-31 07:33:00 +00:00
{
2014-01-25 21:13:42 +00:00
for ( j = 0 ; r - > notesV [ j ] ! = NULL ; + + j )
if ( _cmSdbSelectText ( r , notesV , notSubFlV , notNegFlV , r - > notesV [ j ] ) = = true )
break ;
2014-01-31 07:33:00 +00:00
if ( r - > notesV [ j ] = = NULL )
continue ;
}
2014-01-25 21:13:42 +00:00
_cmSdbRspInsertIndex ( p , rp , i ) ;
}
2014-01-31 07:33:00 +00:00
rhp - > h = rp ;
if ( rc ! = kOkSdbRC )
_cmSdbRspFree ( rp ) ;
2014-01-25 21:13:42 +00:00
return rc ;
}
2014-01-31 07:33:00 +00:00
cmSdbRC_t _cmSdbSelectChPairs ( cmSdb_t * p , const cmSdbEvent_t * ep , cmSdbResponseH_t * rhp )
2014-01-25 21:13:42 +00:00
{
2014-01-31 07:33:00 +00:00
cmSdbRC_t rc ;
if ( ( rc = cmSdbResponseFree ( rhp ) ) ! = kOkSdbRC )
return rc ;
cmSdbRsp_t * rp = _cmSdbRspAlloc ( p ) ;
2014-01-25 21:13:42 +00:00
unsigned i ;
// for each channel of this event
for ( i = 0 ; i < ep - > chCnt ; + + i )
{
// if i channel is not the known events channel
if ( ep - > chIdx ! = i )
{
unsigned j ;
// examine each record
for ( j = 0 ; j < p - > eN ; + + j )
// if eV[j] shares a baseUuid but is on a different channel than *ep ...
if ( p - > eV [ j ] . baseUuid = = ep - > baseUuid & & p - > eV [ j ] . chIdx = = i )
{
// .. then a match has been found
_cmSdbRspInsertIndex ( p , rp , j ) ;
break ;
}
if ( j = = p - > eN )
{
rc = cmErrMsg ( & p - > ctx . err , kChPairNotFoundSdbRC , " The channel pair associated with 'id:%i instr:%s src:%s ch index:%i could not be found. " , ep - > uuid , cmStringNullGuard ( ep - > instr ) , cmStringNullGuard ( ep - > src ) , ep - > chIdx ) ;
}
}
}
2014-01-31 07:33:00 +00:00
rhp - > h = rp ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
return rc ;
2014-01-25 21:13:42 +00:00
}
2014-01-31 07:33:00 +00:00
cmSdbRC_t cmSdbSelectChPairs ( cmSdbH_t h , const cmSdbEvent_t * ep , cmSdbResponseH_t * rhp )
{
cmSdb_t * p = _cmSdbHandleToPtr ( h ) ;
return _cmSdbSelectChPairs ( p , ep , rhp ) ;
}
2014-01-25 21:13:42 +00:00
unsigned cmSdbResponseCount ( cmSdbResponseH_t rh )
{
cmSdbRsp_t * rp = _cmSdbRspHandleToPtr ( rh ) ;
return rp - > cnt ;
}
const cmSdbEvent_t * cmSdbResponseEvent ( cmSdbResponseH_t rh , unsigned index )
{
cmSdbRsp_t * rp = _cmSdbRspHandleToPtr ( rh ) ;
if ( index > = rp - > cnt )
return NULL ;
cmSdbRspBlk_t * bp = rp - > blocks ;
unsigned i ;
for ( i = 0 ; bp ! = NULL ; i + = bp - > cnt , bp = bp - > link )
if ( i < = index & & index < ( i + bp - > cnt ) )
return rp - > p - > eV + bp - > indexV [ index - i ] ;
cmErrMsg ( & rp - > p - > ctx . err , kInvalidRspIdxSdbRC , " Invalid query response index=%i. " , index ) ;
return NULL ;
}
bool cmSdbResponseIsValid ( cmSdbResponseH_t rh )
{ return rh . h ! = NULL ; }
cmSdbRC_t cmSdbResponseFree ( cmSdbResponseH_t * rhp )
{
cmSdbRC_t rc = kOkSdbRC ;
if ( rhp = = NULL | | cmSdbResponseIsValid ( * rhp ) = = false )
return rc ;
cmSdbRsp_t * rp = _cmSdbRspHandleToPtr ( * rhp ) ;
_cmSdbRspFree ( rp ) ;
rhp - > h = NULL ;
return rc ;
}
void cmSdbResponsePrint ( cmSdbResponseH_t rh , cmRpt_t * rpt )
{
unsigned n = cmSdbResponseCount ( rh ) ;
unsigned i ;
for ( i = 0 ; i < n ; + + i )
{
const cmSdbEvent_t * e = cmSdbResponseEvent ( rh , i ) ;
if ( e ! = NULL )
cmRptPrintf ( rpt , " %6i %6i %2i %12i %12i %12i %12i %2i %6i %2i %10s %15s \n " ,
e - > uuid , e - > baseUuid , e - > chIdx , e - > obi , e - > ibi , e - > iei , e - > oei , e - > midi , e - > srate , e - > chCnt ,
cmStringNullGuard ( e - > src ) , cmStringNullGuard ( e - > instr ) ) ;
}
}
2014-01-31 07:33:00 +00:00
//================================================================================================================================
cmSdbSeq_t * _cmSdbSeqHandleToPtr ( cmSdbSeqH_t sh )
2014-01-25 21:13:42 +00:00
{
2014-01-31 07:33:00 +00:00
cmSdbSeq_t * sp = ( cmSdbSeq_t * ) sh . h ;
assert ( sp ! = NULL ) ;
return sp ;
}
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
void _cmSdbSeqInsertEvent ( cmSdbSeq_t * sp , unsigned uuid , unsigned chIdx , double begSecs , double durSecs )
{
cmSdb_t * p = sp - > p ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
// if no block has been allocated or the current block is full
if ( sp - > ebp = = NULL | | sp - > ebp - > cnt > = p - > blkEvtAllocCnt )
{
// allocate a new seq block recd
cmSdbSeqBlk_t * bp = cmLhAllocZ ( sp - > p - > lhH , cmSdbSeqBlk_t , 1 ) ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
// allocate a seq evt array
bp - > eV = cmLhAllocZ ( sp - > p - > lhH , cmSdbSeqEvent_t , p - > blkEvtAllocCnt ) ;
// link in the block recd
if ( sp - > ebp ! = NULL )
sp - > ebp - > link = bp ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
if ( sp - > blocks = = NULL )
{
sp - > blocks = bp ;
sp - > minDurSec = durSecs ;
sp - > maxDurSec = durSecs ;
2014-01-25 21:13:42 +00:00
}
2014-01-31 07:33:00 +00:00
sp - > ebp = bp ;
}
assert ( sp - > ebp ! = NULL & & sp - > ebp - > cnt < p - > blkEvtAllocCnt ) ;
// get the next seq evt recd to fill
cmSdbSeqEvent_t * ep = sp - > ebp - > eV + sp - > ebp - > cnt ;
// fill the seq evt recd
ep - > uuid = uuid ;
ep - > begSec = begSecs ;
ep - > durSec = durSecs ;
ep - > outChIdx = chIdx ;
ep - > gain = 1.0 ;
// incr the seq evt cnt
sp - > ebp - > cnt + = 1 ;
sp - > cnt + = 1 ;
sp - > chCnt = cmMax ( sp - > chCnt , chIdx + 1 ) ;
sp - > minDurSec = cmMin ( sp - > minDurSec , durSecs ) ;
sp - > maxDurSec = cmMax ( sp - > maxDurSec , durSecs ) ;
2014-01-25 21:13:42 +00:00
}
2014-01-31 07:33:00 +00:00
// unlink a sequence record from p->seqs.
cmSdbSeq_t * _cmSdbSeqUnlink ( cmSdbSeq_t * sp )
2014-01-25 21:13:42 +00:00
{
2014-01-31 07:33:00 +00:00
cmSdb_t * p = sp - > p ;
cmSdbSeq_t * cp = p - > seqs ;
cmSdbSeq_t * pp = NULL ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
for ( ; cp ! = NULL ; cp = cp - > link )
2014-01-25 21:13:42 +00:00
{
2014-01-31 07:33:00 +00:00
if ( cp = = sp )
{
if ( pp = = NULL )
p - > seqs = sp - > link ;
else
pp - > link = sp - > link ;
return sp ;
}
pp = cp ;
}
assert ( 0 ) ;
return NULL ;
}
// free a sequence record
cmSdbRC_t _cmSdbSeqFree ( cmSdbSeq_t * sp )
{
cmSdb_t * p = sp - > p ;
// unlink this seq. record from p->seqs
if ( _cmSdbSeqUnlink ( sp ) = = NULL )
return cmErrMsg ( & p - > ctx . err , kAssertFailSdbRC , " Sequence unlink failed. " ) ;
// release the seq blocks held by the sequence
while ( sp - > blocks ! = NULL )
{
cmSdbSeqBlk_t * np = sp - > blocks - > link ;
cmLhFree ( p - > lhH , sp - > blocks - > eV ) ;
cmLhFree ( p - > lhH , sp - > blocks ) ;
sp - > blocks = np ;
}
cmLhFree ( p - > lhH , sp ) ;
return kOkSdbRC ;
}
// allocate a sequence record
cmSdbSeq_t * _cmSdbSeqAlloc ( cmSdb_t * p )
{
cmSdbSeq_t * sp = cmLhAllocZ ( p - > lhH , cmSdbSeq_t , 1 ) ;
sp - > p = p ;
sp - > link = p - > seqs ;
p - > seqs = sp ;
return sp ;
}
cmSdbRC_t _cmSdbStoreSeqEvent (
cmSdb_t * p ,
cmSdbSeq_t * sp ,
cmSdbResponseH_t rh ,
unsigned ri ,
unsigned seqChCnt ,
double begSecs ,
double limitEvtDurSecs ,
double * durSecsRef )
{
2014-02-02 00:26:52 +00:00
cmSdbRC_t rc = kOkSdbRC ;
double maxEvtDurSecs = 0 ;
2014-01-31 07:33:00 +00:00
// retrieve the event record
const cmSdbEvent_t * ep ;
if ( ( ep = cmSdbResponseEvent ( rh , ri ) ) = = NULL )
{
rc = cmErrMsg ( & p - > ctx . err , kRspEvtNotFoundSdbRC , " A response event could not be found during random sequence generation. " ) ;
goto errLabel ;
}
cmSdbResponseH_t rh0 = cmSdbResponseNullHandle ;
unsigned rn0 = 0 ;
unsigned ci = 0 ;
// locate the channel pairs for 'ep'.
if ( seqChCnt > 1 & & ep - > chCnt > 1 )
{
if ( _cmSdbSelectChPairs ( p , ep , & rh0 ) ! = kOkSdbRC )
{
rc = cmErrMsg ( & p - > ctx . err , kChPairNotFoundSdbRC , " A response event could not find channel pairs during random sequence generation. " ) ;
goto errLabel ;
}
rn0 = cmSdbResponseCount ( rh0 ) ;
}
while ( 1 )
{
// calculate the event duration
double durSecs = ( double ) ( ep - > oei - ep - > obi ) / ep - > srate ;
// truncate the event if it is longer than limitEvtDurSecs
if ( limitEvtDurSecs ! = 0 & & durSecs > limitEvtDurSecs )
durSecs = cmMin ( limitEvtDurSecs , durSecs ) ;
// track the longest event
maxEvtDurSecs = cmMax ( maxEvtDurSecs , durSecs ) ;
// store the sequence event
_cmSdbSeqInsertEvent ( sp , ep - > uuid , ci , begSecs , durSecs ) ;
// incr the output ch index
+ + ci ;
// if all the out ch's are filled or the sample event has no more channels
if ( ci > = seqChCnt | | ci - 1 > = rn0 )
break ;
// get the next channel pair
if ( ( ep = cmSdbResponseEvent ( rh0 , ci - 1 ) ) = = NULL )
{
rc = cmErrMsg ( & p - > ctx . err , kRspEvtNotFoundSdbRC , " A channel pair response event could not be found during random sequence generation. " ) ;
goto errLabel ;
}
} // for each sample event pair
errLabel :
if ( durSecsRef ! = NULL )
* durSecsRef = maxEvtDurSecs ;
cmSdbResponseFree ( & rh0 ) ;
return rc ;
}
cmSdbRC_t cmSdbSeqRand (
cmSdbResponseH_t rh ,
unsigned seqDurSecs ,
unsigned seqChCnt ,
unsigned minEvtPerSec ,
unsigned maxEvtPerSec ,
cmSdbSeqH_t * shp )
{
cmSdbRC_t rc ;
if ( ( rc = cmSdbSeqFree ( shp ) ) ! = kOkSdbRC )
return rc ;
cmSdbRsp_t * rp = _cmSdbRspHandleToPtr ( rh ) ;
cmSdb_t * p = rp - > p ;
cmSdbSeq_t * sp = _cmSdbSeqAlloc ( p ) ;
if ( seqChCnt < 1 )
return cmErrMsg ( & p - > ctx . err , kInvalidArgSdbRC , " The random sequence generator channel count parameter must be non-zero. " ) ;
if ( seqDurSecs < = 0 )
return cmErrMsg ( & p - > ctx . err , kInvalidArgSdbRC , " The random sequence generator signal duration must be greater than 0. " ) ;
if ( maxEvtPerSec < minEvtPerSec )
return cmErrMsg ( & p - > ctx . err , kInvalidArgSdbRC , " The random sequence generator max. events per second must be greater or equal to the min. events per second. " ) ;
if ( ( rc = cmSdbSeqFree ( shp ) ) ! = kOkSdbRC )
return rc ;
unsigned rn = cmSdbResponseCount ( rh ) ;
unsigned sec ;
for ( sec = 0 ; sec < seqDurSecs ; sec + = 1 )
{
// calcuate the number of events to initiate during this second
unsigned en = cmRandUInt ( minEvtPerSec , maxEvtPerSec ) ;
unsigned ei ;
for ( ei = 0 ; ei < en ; + + ei )
{
// select an event index
unsigned ri = cmRandUInt ( 0 , rn - 1 ) ;
// double select a start time for this event
double begSecs = sec + cmRandDouble ( 0.0 , 1.0 ) ;
double maxEvtDurSecs = 0 ;
if ( ( rc = _cmSdbStoreSeqEvent ( p , sp , rh , ri , seqChCnt , begSecs , maxEvtDurSecs , NULL ) ) ! = kOkSdbRC )
goto errLabel ;
} // for each event init'd during this second
} // for each second
shp - > h = sp ;
errLabel :
if ( rc ! = kOkSdbRC )
_cmSdbSeqFree ( sp ) ;
return rc ;
}
cmSdbRC_t cmSdbSeqSerial (
cmSdbResponseH_t rh ,
unsigned seqChCnt ,
double gapSec ,
double maxEvtDurSec ,
cmSdbSeqH_t * shp )
{
cmSdbRC_t rc ;
if ( ( rc = cmSdbSeqFree ( shp ) ) ! = kOkSdbRC )
return rc ;
cmSdbRsp_t * rp = _cmSdbRspHandleToPtr ( rh ) ;
cmSdb_t * p = rp - > p ;
cmSdbSeq_t * sp = _cmSdbSeqAlloc ( p ) ;
unsigned n = cmSdbResponseCount ( rh ) ;
double begSecs = 0 ;
unsigned ri ;
for ( ri = 0 ; ri < n ; + + ri )
{
double durSecs = 0 ;
if ( ( rc = _cmSdbStoreSeqEvent ( p , sp , rh , ri , seqChCnt , begSecs , maxEvtDurSec , & durSecs ) ) ! = kOkSdbRC )
goto errLabel ;
// offset to next event
begSecs + = durSecs + gapSec ;
}
shp - > h = sp ;
errLabel :
if ( rc ! = kOkSdbRC )
_cmSdbSeqFree ( sp ) ;
return rc ;
}
cmSdbRC_t cmSdbSeqChord (
cmSdbResponseH_t * rhp ,
unsigned rn ,
unsigned seqChCnt ,
unsigned maxEvtDurSec ,
cmSdbSeqH_t * shp )
{
cmSdbRC_t rc = kOkSdbRC ;
assert ( shp ! = NULL ) ;
if ( rn = = 0 )
return rc ;
cmSdbResponseH_t rh = rhp [ 0 ] ;
cmSdbRsp_t * rp = _cmSdbRspHandleToPtr ( rh ) ;
cmSdb_t * p = rp - > p ;
cmSdbSeq_t * sp = _cmSdbSeqAlloc ( p ) ;
unsigned i ;
if ( ( rc = cmSdbSeqFree ( shp ) ) ! = kOkSdbRC )
return rc ;
// for each chord note
for ( i = 0 ; i < rn ; + + i )
{
// get the query response handle for this note
rh = rhp [ i ] ;
rp = _cmSdbRspHandleToPtr ( rh ) ;
// verify that all query responses were drawn from the same cmSdbH_t handle.
if ( rp - > p ! = p )
{
rc = cmErrMsg ( & p - > ctx . err , kAssertFailSdbRC , " All chord query response handle must be derived from the same cmSdbH_t handle. " ) ;
goto errLabel ;
}
// pick one event at random from the response
unsigned n = cmSdbResponseCount ( rh ) ;
unsigned rei = cmRandUInt ( 0 , n - 1 ) ;
// all notes start at time: 0.0.
double begSecs = 0.0 ;
// store the sequence event
if ( ( rc = _cmSdbStoreSeqEvent ( p , sp , rh , rei , seqChCnt , begSecs , maxEvtDurSec , NULL ) ) ! = kOkSdbRC )
goto errLabel ;
}
shp - > h = sp ;
errLabel :
if ( rc ! = kOkSdbRC )
_cmSdbSeqFree ( sp ) ;
return rc ;
}
bool cmSdbSeqIsValid ( cmSdbSeqH_t sh )
{ return sh . h ! = NULL ; }
cmSdbRC_t cmSdbSeqFree ( cmSdbSeqH_t * shp )
{
cmSdbRC_t rc = kOkSdbRC ;
if ( shp = = NULL | | cmSdbSeqIsValid ( * shp ) = = false )
return rc ;
cmSdbSeq_t * sp = _cmSdbSeqHandleToPtr ( * shp ) ;
if ( ( rc = _cmSdbSeqFree ( sp ) ) ! = kOkSdbRC )
return rc ;
shp - > h = NULL ;
return rc ;
}
unsigned cmSdbSeqCount ( cmSdbSeqH_t sh )
{
if ( cmSdbSeqIsValid ( sh ) = = false )
return 0 ;
cmSdbSeq_t * sp = _cmSdbSeqHandleToPtr ( sh ) ;
return sp - > cnt ;
}
const cmSdbSeqEvent_t * cmSdbSeqEvent ( cmSdbSeqH_t sh , unsigned index )
{
cmSdbSeq_t * sp = _cmSdbSeqHandleToPtr ( sh ) ;
if ( index > = sp - > cnt )
return NULL ;
cmSdbSeqBlk_t * bp = sp - > blocks ;
unsigned i ;
for ( i = 0 ; bp ! = NULL ; i + = bp - > cnt , bp = bp - > link )
if ( i < = index & & index < ( i + bp - > cnt ) )
return bp - > eV + index - i ;
cmErrMsg ( & sp - > p - > ctx . err , kInvalidSeqIdxSdbRC , " Invalid sequence event index=%i. " , index ) ;
return NULL ;
}
const cmSdbEvent_t * cmSdbSeqSdbEvent ( cmSdbSeqH_t sh , unsigned index )
{
const cmSdbSeqEvent_t * ep ;
if ( ( ep = cmSdbSeqEvent ( sh , index ) ) = = NULL )
return NULL ;
cmSdbSeq_t * sp = _cmSdbSeqHandleToPtr ( sh ) ;
return _cmSdbEvent ( sp - > p , ep - > uuid ) ;
}
double cmSdbSeqDurSeconds ( cmSdbSeqH_t sh )
{
cmSdbSeq_t * sp = _cmSdbSeqHandleToPtr ( sh ) ;
cmSdbSeqBlk_t * bp = sp - > blocks ;
while ( bp ! = NULL & & bp - > link ! = NULL )
bp = bp - > link ;
if ( bp = = NULL )
return 0 ;
cmSdbSeqEvent_t * ep = bp - > eV + bp - > cnt - 1 ;
return ep - > begSec + ep - > durSec ;
}
double cmSdbSeqSampleRate ( cmSdbSeqH_t sh )
{
unsigned n = cmSdbSeqCount ( sh ) ;
unsigned i ;
const cmSdbEvent_t * ep ;
for ( i = 0 ; i < n ; + + i )
if ( ( ep = cmSdbSeqSdbEvent ( sh , i ) ) ! = NULL & & ep - > srate ! = 0 )
return ep - > srate ;
return 0 ;
}
cmSdbRC_t cmSdbSeqToAudio (
cmSdbSeqH_t sh ,
unsigned decayMs ,
double noiseDb ,
double normFact ,
cmSample_t * * signalRef ,
unsigned * sigSmpCntRef )
{
assert ( signalRef ! = NULL & & sigSmpCntRef ! = NULL ) ;
* signalRef = NULL ;
* sigSmpCntRef = 0 ;
cmSdbRC_t rc = kOkSdbRC ;
cmSdbSeq_t * sp = _cmSdbSeqHandleToPtr ( sh ) ;
cmSdb_t * p = sp - > p ;
unsigned qN = cmSdbSeqCount ( sh ) ;
double durSecs = cmSdbSeqDurSeconds ( sh ) ;
double srate = cmSdbSeqSampleRate ( sh ) ;
assert ( sp - > maxDurSec > = sp - > minDurSec ) ;
// verify that sequence events exist
if ( qN = = 0 | | durSecs = = 0 | | sp - > chCnt = = 0 | | sp - > maxDurSec = = 0 )
return rc ;
// validate the sample rate
if ( srate = = 0 )
return cmErrMsg ( & p - > ctx . err , kAssertFailSdbRC , " The sample rate of the sequence could not be determined. " ) ;
unsigned sN = ( unsigned ) floor ( srate * ( durSecs + 0.25 ) ) ; // output signal sample count + 1/4 second of silence
unsigned dN = ( unsigned ) floor ( srate * decayMs / 1000.0 ) ; // decay env. sample count
unsigned tN = ( unsigned ) floor ( srate * sp - > maxDurSec ) ; // length of longest audio event in samples
cmSample_t * s = cmMemAllocZ ( cmSample_t , sN * sp - > chCnt ) ; // allocate the outputsignal buffer
cmSample_t * t = cmMemAllocZ ( cmSample_t , tN * sp - > chCnt ) ; // audio event read buffer
cmSample_t * d = NULL ;
cmSample_t * chBuf [ sp - > chCnt ] ;
unsigned i ;
// fill the channel buffers
for ( i = 0 ; i < sp - > chCnt ; + + i )
chBuf [ i ] = t + ( i * tN ) ;
// if a decay rate was specified
if ( dN > 0 )
{
d = cmMemAllocZ ( cmSample_t , dN ) ; // allocate the decay env. buffer
cmVOS_LinSpace ( d , dN , 1.0 , 0.0 ) ; // calc. a decay envelope
cmVOS_PowVS ( d , dN , 4.0 ) ;
}
// if a noise floor was specified
if ( noiseDb ! = 0 )
{
// fill the signal with low level white noise
cmVOS_Random ( s , sN , - 1.0 , 1.0 ) ;
cmVOS_MultVS ( s , sN , pow ( 10.0 , - fabs ( noiseDb ) / 20.0 ) ) ;
}
// for each sequence event
for ( i = 0 ; rc = = kOkSdbRC & & i < qN ; + + i )
{
const cmSdbSeqEvent_t * qep ;
const cmSdbEvent_t * ep ;
// get the sequence event record
if ( ( qep = cmSdbSeqEvent ( sh , i ) ) = = NULL )
{
rc = cmErrMsg ( & p - > ctx . err , kAssertFailSdbRC , " Unable to retrieve the sequence event at index %i. " , i ) ;
goto errLabel ;
}
// get the audio event record
if ( ( ep = _cmSdbEvent ( p , qep - > uuid ) ) = = NULL )
{
rc = cmErrMsg ( & p - > ctx . err , kAssertFailSdbRC , " Unable to retrieve the sample event with uuid:%i. " , qep - > uuid ) ;
goto errLabel ;
}
unsigned begFrmIdx = floor ( srate * qep - > begSec ) ; // dest. index into output signal
unsigned frmCnt = floor ( srate * qep - > durSec ) ; // seq. event dur in samples
const cmChar_t * afn = NULL ; // audio event file name
unsigned actFrmCnt = 0 ; // actual count of samples read from the audio event file
cmAudioFileInfo_t afInfo ; // audio file info. record
// form the audio event file name
if ( ( afn = cmFsMakeFn ( p - > audioDir , ep - > afn , NULL , NULL ) ) = = NULL )
{
rc = cmErrMsg ( & p - > ctx . err , kFileSysFailSdbRC , " Unable to form the file name for %s/%s. " , cmStringNullGuard ( p - > audioDir ) , cmStringNullGuard ( ep - > afn ) ) ;
goto errLabel ;
}
assert ( ep - > oei - ep - > obi > 0 ) ;
// read the audio event from the file into t[]
if ( cmAudioFileGetSample ( afn , ep - > obi , cmMin ( tN , cmMin ( frmCnt , ep - > oei - ep - > obi ) ) , 0 , ep - > chCnt , chBuf , & actFrmCnt , & afInfo , p - > ctx . err . rpt ) ! = kOkAfRC )
{
rc = cmErrMsg ( & p - > ctx . err , kFileSysFailSdbRC , " Audio event read failed for event uuid:%i in '%s'. " , qep - > uuid , cmStringNullGuard ( afn ) ) ;
goto doneLabel ;
}
// 'actFrmCnt' now holds the length of the event signal
// verify that the audio event sample rate matches the sequence srate
if ( afInfo . srate ! = srate )
cmErrWarnMsg ( & p - > ctx . err , kAssertFailSdbRC , " The sample rate (%f) of audio event uuid:%i in '%s' does not match the sequence sample rate:%f. " , afInfo . srate , qep - > uuid , cmStringNullGuard ( afn ) , srate ) ;
// if a decay rate was specified
if ( dN > 0 )
{
unsigned ti = 0 ; // start of decay in t[]
unsigned di = 0 ; // start of decay in d[]
if ( actFrmCnt > dN )
ti = actFrmCnt - dN ; // decay func is applied to end of audio event
else
di = dN - actFrmCnt ; // decay func is longer than audio event (shorten it)
unsigned mn = dN - di ; // decay function length
unsigned j ;
// apply the decay function
for ( j = 0 ; j < sp - > chCnt ; + + j )
cmVOS_MultVV ( t + ( j * tN ) + ti , mn , d + di ) ;
}
// normalize the event signal
if ( normFact ! = 0 )
cmVOS_NormToAbsMax ( t , actFrmCnt , normFact ) ;
// verify the the signal event falls inside the output signal
if ( begFrmIdx > = sN )
rc = cmErrMsg ( & p - > ctx . err , kAssertFailSdbRC , " A sequence event start time falls after the end of the sequence signal. This should never happen. " ) ;
else
{
// if the event signal goes past the end of the signal - truncate the event
if ( begFrmIdx + actFrmCnt > sN )
actFrmCnt = sN - begFrmIdx ;
// sum the event signal into the output signal
cmVOS_AddVV ( s + ( qep - > outChIdx * sN ) + begFrmIdx , actFrmCnt , t ) ;
}
doneLabel :
cmFsFreeFn ( afn ) ;
}
* signalRef = s ;
* sigSmpCntRef = sN ;
errLabel :
if ( rc ! = kOkSdbRC )
cmMemFree ( s ) ;
cmMemFree ( d ) ;
cmMemFree ( t ) ;
return rc ;
}
cmSdbRC_t cmSdbSeqToAudioFn (
cmSdbSeqH_t sh ,
unsigned decayMs ,
double noiseDb ,
double evtNormFact ,
double sigNormFact ,
const cmChar_t * fn ,
unsigned bitsPerSample
)
{
cmSdbRC_t rc = kOkSdbRC ;
cmSample_t * s = NULL ;
unsigned sN = 0 ;
cmSdbSeq_t * sp = _cmSdbSeqHandleToPtr ( sh ) ;
cmSdb_t * p = sp - > p ;
double srate = cmSdbSeqSampleRate ( sh ) ;
unsigned i ;
// fill s[sN] with the sequence audio signal
if ( ( rc = cmSdbSeqToAudio ( sh , decayMs , noiseDb , evtNormFact , & s , & sN ) ) ! = kOkSdbRC )
return rc ;
// if no audio signal was created there is nothing to do
if ( sN = = 0 )
return rc ;
// the sample rate was already check by cmSdbSeqToAudio().
assert ( srate ! = 0 & & s ! = NULL ) ;
// if requested normalize the signal
if ( sigNormFact ! = 0 )
cmVOS_NormToAbsMax ( s , sN * sp - > chCnt , sigNormFact ) ;
// fill the channel buffer
cmSample_t * chBuf [ sp - > chCnt ] ;
for ( i = 0 ; i < sp - > chCnt ; + + i )
chBuf [ i ] = s + ( i * sN ) ;
// write the signal to an audio file
if ( ( rc = cmAudioFileWriteFileFloat ( fn , srate , bitsPerSample , sN , sp - > chCnt , chBuf , p - > ctx . err . rpt ) ) ! = kOkAfRC )
{
rc = cmErrMsg ( & p - > ctx . err , kAudioFileFailSdbRC , " The sequence audio file '%s' could not be created. " , cmStringNullGuard ( fn ) ) ;
goto errLabel ;
}
errLabel :
cmMemFree ( s ) ;
return rc ;
}
void cmSdbSeqPrint ( cmSdbSeqH_t sh , cmRpt_t * rpt )
{
unsigned i ;
unsigned n = cmSdbSeqCount ( sh ) ;
cmSdbSeq_t * sp = _cmSdbSeqHandleToPtr ( sh ) ;
const cmSdbSeqEvent_t * ep ;
cmRptPrintf ( rpt , " evt cnt:%i ch cnt:%i dur min:%f max:%f \n " , sp - > cnt , sp - > chCnt , sp - > minDurSec , sp - > maxDurSec ) ;
cmRptPrintf ( rpt , " uuid ch beg dur gain \n " ) ;
cmRptPrintf ( rpt , " ------- --- ------- ------- ------- \n " ) ;
for ( i = 0 ; i < n ; + + i )
if ( ( ep = cmSdbSeqEvent ( sh , i ) ) ! = NULL )
cmRptPrintf ( rpt , " %7i %3i %7.3f %7.3f %7.3f \n " , ep - > uuid , ep - > outChIdx , ep - > begSec , ep - > durSec , ep - > gain ) ;
}
cmSdbRC_t cmSdbTest ( cmCtx_t * ctx )
{
cmSdbRC_t rc = kOkSdbRC ;
cmSdbH_t h = cmSdbNullHandle ;
const cmChar_t * audioDir = " /home/kevin/media/audio " ;
const cmChar_t * csvFn = " /home/kevin/temp/sdb0/sdb_master.csv " ;
cmErr_t err ;
cmErrSetup ( & err , & ctx - > rpt , " sdb test " ) ;
if ( ( rc = cmSdbCreate ( ctx , & h , csvFn , audioDir ) ) ! = kOkSdbRC )
{
rc = cmErrMsg ( & err , rc , " sdb create failed. " ) ;
goto errLabel ;
}
if ( ( rc = cmSdbSyncChPairs ( h ) ) ! = kOkSdbRC )
2014-01-25 21:13:42 +00:00
{
rc = cmErrMsg ( & err , rc , " sdb sync-ch-pairs failed. " ) ;
goto errLabel ;
}
2014-01-31 07:33:00 +00:00
if ( 1 )
2014-01-25 21:13:42 +00:00
{
cmSdbResponseH_t rH = cmSdbResponseNullHandle ;
2014-01-31 07:33:00 +00:00
cmSdbSeqH_t sH = cmSdbSeqNullHandle ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
const cmChar_t * instrV [ ] = { " violin " , NULL } ;
const cmChar_t * srcV [ ] = { " ui " , NULL } ;
const cmChar_t * notesV [ ] = { " !vibrato " , NULL } ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
if ( ( rc = cmSdbSelect ( h , 0 , instrV , srcV , notesV , NULL , 0 , 0 , 0 , & rH ) ) ! = kOkSdbRC )
2014-01-25 21:13:42 +00:00
{
rc = cmErrMsg ( & err , rc , " sdb query failed. " ) ;
goto errLabel ;
}
2014-01-31 07:33:00 +00:00
//cmSdbResponsePrint(rH,&ctx->rpt);
unsigned seqDurSecs = 15 ;
unsigned seqChCnt = 2 ;
unsigned sel = 2 ;
switch ( sel )
{
case 0 :
{
unsigned minEvtPerSec = 1 ;
unsigned maxEvtPerSec = 5 ;
if ( ( rc = cmSdbSeqRand ( rH , seqDurSecs , seqChCnt , minEvtPerSec , maxEvtPerSec , & sH ) ) ! = kOkSdbRC )
{
rc = cmErrMsg ( & err , rc , " sdb random sequence generation failed. " ) ;
goto errLabel ;
}
}
break ;
case 1 :
{
double gapSec = 0.1 ;
double maxEvtDurSec = 1.0 ;
if ( ( rc = cmSdbSeqSerial ( rH , seqChCnt , gapSec , maxEvtDurSec , & sH ) ) ! = kOkSdbRC )
{
rc = cmErrMsg ( & err , rc , " sdb serial sequence generation failed. " ) ;
goto errLabel ;
}
}
break ;
case 2 :
{
cmSdbResponseH_t rhV [ ] = { rH , rH , rH } ;
unsigned rN = sizeof ( rhV ) / sizeof ( rhV [ 0 ] ) ;
double maxEvtDurSec = 1.0 ;
if ( ( rc = cmSdbSeqChord ( rhV , rN , seqChCnt , maxEvtDurSec , & sH ) ) ! = kOkSdbRC )
{
rc = cmErrMsg ( & err , rc , " sdb chord sequence generation failed. " ) ;
goto errLabel ;
}
}
break ;
}
cmSdbSeqPrint ( sH , & ctx - > rpt ) ;
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
const cmChar_t * afn = " /home/kevin/temp/aaa.aif " ;
unsigned decayMs = 50 ;
double noiseDb = - 70.0 ;
double evtNormFact = 0 ; //0.7;
double sigNormFact = 0.7 ; //0.7;
unsigned bitsPerSample = 16 ;
if ( ( rc = cmSdbSeqToAudioFn ( sH , decayMs , noiseDb , evtNormFact , sigNormFact , afn , bitsPerSample ) ) ! = kOkSdbRC )
{
rc = cmErrMsg ( & err , rc , " sdb sequence audio file generation failed. " ) ;
goto errLabel ;
}
2014-01-25 21:13:42 +00:00
2014-01-31 07:33:00 +00:00
cmSdbSeqFree ( & sH ) ;
2014-01-25 21:13:42 +00:00
cmSdbResponseFree ( & rH ) ;
}
errLabel :
if ( ( rc = cmSdbDestroy ( & h ) ) ! = kOkSdbRC )
rc = cmErrMsg ( & err , rc , " sdb destroy failed. " ) ;
return rc ;
}