2012-10-30 03:52:39 +00:00
# include "cmPrefix.h"
# include "cmGlobal.h"
# include "cmRpt.h"
# include "cmErr.h"
# include "cmMem.h"
# include "cmMallocDebug.h"
2013-12-15 23:28:11 +00:00
# include "cmTime.h"
2012-10-30 03:52:39 +00:00
# include "cmAudioPort.h"
# include "cmApBuf.h"
# include "cmThread.h"
/*
This API is in general called by two types of threads :
audio devices threads and the client thread . There
may be multiple devie threads however there is only
one client thread .
The audio device threads only call cmApBufUpdate ( ) .
cmApBufUpdate ( ) is never called by any other threads .
A call from the audio update threads targets specific channels
( cmApCh records ) . The variables within each channels that
it modifies are confined to :
on input channels : increments ii and increments fn ( data is entering the ch . buffers )
on output channels : increments oi and decrements fn ( data is leaving the ch . buffers )
The client picks up incoming audio and provides outgoing audio via
cmApBufGet ( ) . It then informs the cmApBuf ( ) that it has completed
the audio data transfer by calling cmApBufAdvance ( ) .
cmApBufAdvance ( ) modifies the following internal variables :
on input channels : increments oi and decrements fn ( data has left the ch buffer )
on output channels : increments ii and increments fn ( data has enterned the ch . buffer )
Based on the above scenario the channel ii and oi variables are always thread - safe
because they are only changed by a single thread .
ii oi fn
- - - - - - - - - - - - - - -
input ch : audio client both
output ch : client audio both
The fn variable however is not thread - safe and therefore care must be taken as
2020-02-29 17:31:01 +00:00
to how it is read and updated .
2012-10-30 03:52:39 +00:00
*/
enum { kInApIdx = 0 , kOutApIdx = 1 , kIoApCnt = 2 } ;
typedef struct
{
unsigned fl ; // kChApFl|kToneApFl|kMeterApFl ...
cmApSample_t * b ; // b[n]
unsigned ii ; // next in
unsigned oi ; // next out
unsigned fn ; // full cnt - count of samples currently in the buffer - incr'd by incoming, decr'd by outgoing
unsigned phs ; // tone phase
double hz ; // tone frequency
double gain ; // channel gain
cmApSample_t * m ; // m[mn] meter sample sum
unsigned mn ; // length of m[]
unsigned mi ; // next ele of m[] to rcv sum
2020-02-29 17:31:01 +00:00
cmApSample_t s0 ; // buffered sample used for srate conversion
2012-10-30 03:52:39 +00:00
} cmApCh ;
typedef struct
{
2020-02-29 17:31:01 +00:00
unsigned chCnt ; // Count of channels
cmApCh * chArray ; // chArray[chCnt] channel record array
2012-10-30 03:52:39 +00:00
2020-02-29 17:31:01 +00:00
unsigned n ; // Length of b[] (multiple of dspFrameCnt) bufCnt*framesPerCycle
double srate ; // Device sample rate;
int srateMult ; // Internal sample rate multiplier (negative values for dividing). This srateMult*srate is the sample rate of
// signals held in the chApCh[] input and output buffers. Sample rate conversion to/from this rate
// occurs in cmApBufUpdate() as signals go from/to the audio device.
2012-10-30 03:52:39 +00:00
2020-02-29 17:31:01 +00:00
unsigned faultCnt ; // error count since start
unsigned framesPerCycle ; // expected count of frames per channel to/from the audio device on each call to cmApBufUpdate()
unsigned dspFrameCnt ; // number of frames per channel in buffers returned by cmApBufGet().
cmTimeSpec_t timeStamp ; // base (starting) time stamp for this device
unsigned ioFrameCnt ; // count of frames input or output for this device
2012-10-30 03:52:39 +00:00
} cmApIO ;
typedef struct
{
// ioArray[] always contains 2 elements - one for input the other for output.
cmApIO ioArray [ kIoApCnt ] ;
} cmApDev ;
typedef struct
{
cmApDev * devArray ;
unsigned devCnt ;
unsigned meterMs ;
cmApSample_t * zeroBuf ; // buffer of zeros
unsigned zeroBufCnt ; // max of all dspFrameCnt for all devices.
2020-02-29 17:31:01 +00:00
unsigned abufIdx ;
cmApSample_t abuf [ 16384 ] ;
2012-10-30 03:52:39 +00:00
} cmApBuf ;
cmApBuf _cmApBuf ;
2020-02-29 17:31:01 +00:00
// Copy the source channel (srcChIdx) to the destination buffer and apply up-sampling.
// 'src' is an interleaved buffer with 'srcN' samples per channel and 'srcChN' channels (total size in samples = srcN*srcChN)
// 'dst' is a non-interleaved (single channel) circular buffer of length 'dstN' where 'dstIdx' is the index of the first dst slot to receive a sample..
// Return the index into dst[] of the next location to receive an incoming sample.
unsigned _cmApCopyInUpSample ( const cmApSample_t * src , unsigned srcN , unsigned srcChN , unsigned srcChIdx , cmApSample_t * dst , unsigned dstN , unsigned dstIdx , unsigned mult , double gain , cmApSample_t * s0_Ref )
{
cmApSample_t s0 = * s0_Ref ;
unsigned si , k , di = dstIdx ;
for ( si = 0 ; si < srcN ; + + si )
{
cmApSample_t s1 = src [ si * srcChN + srcChIdx ] ;
for ( k = 1 ; k < mult ; + + k )
{
dst [ di ] = gain * ( s0 + ( s1 - s0 ) * k / mult ) ;
di = ( di + 1 ) % dstN ;
}
dst [ di ] = gain * s1 ;
di = ( di + 1 ) % dstN ;
s0 = s1 ;
}
* s0_Ref = s0 ;
return di ;
}
// Copy the source channel (srcChIdx) to the destination buffer and apply down-sampling.
// 'src' is an interleaved linear buffer with 'srcN' samples per channel and 'srcChN' channels,
// 'dst' is a non-interleaved circular buffer of length 'dstN' where 'dstIdx' is the index of the first dst slot to receive a sample..
// Return the index into dst[] of the next location to receive an incoming sample.
unsigned _cmApCopyInDnSample ( const cmApSample_t * src , unsigned srcN , unsigned srcChN , unsigned srcChIdx , cmApSample_t * dst , unsigned dstN , unsigned dstIdx , unsigned div , double gain )
{
unsigned si , di = dstIdx ;
for ( si = 0 ; si < srcN ; si + = div )
{
dst [ di ] = gain * src [ si * srcChN + srcChIdx ] ;
di = ( di + 1 ) % dstN ;
}
return di ;
}
// Copy samples from an interleaved src buffer to a non-interleaved dst buffer with sample rate conversion
unsigned _cmApCopyInSamples ( const cmApSample_t * src , unsigned srcN , unsigned srcChN , unsigned srcChIdx , cmApSample_t * dst , unsigned dstN , unsigned dstIdx , int srateMult , double gain , cmApSample_t * s0_Ref )
{
if ( srateMult < 1 )
return _cmApCopyInDnSample ( src , srcN , srcChN , srcChIdx , dst , dstN , dstIdx , - srateMult , gain ) ;
return _cmApCopyInUpSample ( src , srcN , srcChN , srcChIdx , dst , dstN , dstIdx , srateMult , gain , s0_Ref ) ;
}
void printBuf ( const cmApSample_t * src , unsigned srcN , unsigned bi , unsigned n )
{
unsigned i , j ;
for ( i = bi , j = 0 ; j < n ; + + i , + + j )
{
i = i % srcN ;
printf ( " (%i,%i,%f), \n " , j , i , src [ i ] ) ;
}
printf ( " ----- \n " ) ;
}
// Copy
// 'src' is a non-interleaved circular buf of total length 'srcN', with the first sample coming at 'srcIdx'.
// 'dst' is an interleaved buffer of length 'dstN' with 'dstChN' channels
// Return the index of the next src sample.
unsigned _cmApCopyOutUpSample ( const cmApSample_t * src , unsigned srcN , unsigned srcIdx , cmApSample_t * dst , unsigned dstN , unsigned dstChN , unsigned dstChIdx , int mult , double gain , cmApSample_t * s0_Ref )
{
unsigned di , si = srcIdx ;
cmApSample_t s0 = * s0_Ref ;
for ( di = 0 ; di < dstN ; + + di )
{
cmApSample_t s1 = src [ si ] ;
unsigned k ;
for ( k = 1 ; k < mult & & di < dstN ; + + di , + + k )
{
dst [ di * dstChN + dstChIdx ] = gain * ( s0 + ( s1 - s0 ) * k / mult ) ;
}
if ( di < dstN )
{
dst [ di * dstChN + dstChIdx ] = gain * s1 ;
+ + di ;
}
si = ( si + 1 ) % srcN ;
s0 = s1 ;
}
* s0_Ref = s0 ;
return si ;
}
// 'src' is a non-interleaved (single channel) circular buf of total length 'srcN', with the first sample coming at 'srcIdx'.
// 'dst' is an interleaved buffer of length 'dstN' with 'dstChN' channels
// Return the index of the next src sample.
unsigned _cmApCopyOutDnSample ( const cmApSample_t * src , unsigned srcN , unsigned srcIdx , cmApSample_t * dst , unsigned dstN , unsigned dstChN , unsigned dstChIdx , int div , double gain )
{
unsigned di , si ;
// The total count of output samples is determined by 'dstN'
// Downsampling is acheived by advancing the src index by 'div' samples.
for ( di = 0 , si = srcIdx ; di < dstN ; + + di )
{
dst [ di * dstChN + dstChIdx ] = gain * src [ si ] ;
si = ( si + div ) % srcN ;
}
return si ;
}
// Copy samples from a non-interleaved src buffer to an interleaved dst buffer with sample rate conversion
unsigned _cmApCopyOutSamples ( const cmApSample_t * src , unsigned srcN , unsigned srcIdx , cmApSample_t * dst , unsigned dstN , unsigned dstChN , unsigned dstChIdx , int srateMult , double gain , cmApSample_t * s0_Ref )
{
if ( srateMult > 0 )
return _cmApCopyOutDnSample ( src , srcN , srcIdx , dst , dstN , dstChN , dstChIdx , srateMult , gain ) ;
return _cmApCopyOutUpSample ( src , srcN , srcIdx , dst , dstN , dstChN , dstChIdx , - srateMult , gain , s0_Ref ) ;
}
2012-10-30 03:52:39 +00:00
cmApSample_t _cmApMeterValue ( const cmApCh * cp )
{
double sum = 0 ;
unsigned i ;
for ( i = 0 ; i < cp - > mn ; + + i )
sum + = cp - > m [ i ] ;
2013-04-09 06:00:40 +00:00
return cp - > mn = = 0 ? 0 : ( cmApSample_t ) sqrt ( sum / cp - > mn ) ;
2012-10-30 03:52:39 +00:00
}
2020-02-29 17:31:01 +00:00
void _cmApSine0 ( cmApCh * cp , cmApSample_t * b0 , unsigned n0 , cmApSample_t * b1 , unsigned n1 , unsigned stride , float srate )
2012-10-30 03:52:39 +00:00
{
unsigned i ;
for ( i = 0 ; i < n0 ; + + i , + + cp - > phs )
b0 [ i * stride ] = ( float ) ( cp - > gain * sin ( 2.0 * M_PI * cp - > hz * cp - > phs / srate ) ) ;
for ( i = 0 ; i < n1 ; + + i , + + cp - > phs )
b1 [ i * stride ] = ( float ) ( cp - > gain * sin ( 2.0 * M_PI * cp - > hz * cp - > phs / srate ) ) ;
}
2020-02-29 17:31:01 +00:00
// Synthesize a sine signal of length sigN*srateMult starting at dst[dstidx]
// Assume dst[dstN] is a circular buffer
unsigned _cmApSine ( cmApCh * cp , cmApSample_t * dst , unsigned dstN , unsigned dstIdx , unsigned dstChCnt , unsigned sigN , unsigned srateMult , float srate , double gain )
{
unsigned i , di ;
sigN = srateMult < 0 ? sigN / abs ( srateMult ) : sigN * srateMult ;
for ( i = 0 , di = dstIdx ; i < sigN ; + + i , + + cp - > phs )
{
dst [ di ] = ( cmApSample_t ) ( gain * sin ( 2.0 * M_PI * cp - > hz * cp - > phs / srate ) ) ;
di = ( di + dstChCnt ) % dstN ;
}
return sigN ;
}
2012-10-30 03:52:39 +00:00
cmApSample_t _cmApMeter ( const cmApSample_t * b , unsigned bn , unsigned stride )
{
const cmApSample_t * ep = b + bn ;
cmApSample_t sum = 0 ;
for ( ; b < ep ; b + = stride )
sum + = * b * * b ;
return sum / bn ;
}
void _cmApChFinalize ( cmApCh * chPtr )
{
cmMemPtrFree ( & chPtr - > b ) ;
cmMemPtrFree ( & chPtr - > m ) ;
}
// n=buf sample cnt mn=meter buf smp cnt
void _cmApChInitialize ( cmApCh * chPtr , unsigned n , unsigned mn )
{
_cmApChFinalize ( chPtr ) ;
chPtr - > b = n = = 0 ? NULL : cmMemAllocZ ( cmApSample_t , n ) ;
chPtr - > ii = 0 ;
chPtr - > oi = 0 ;
chPtr - > fn = 0 ;
chPtr - > fl = ( n ! = 0 ? kChApFl : 0 ) ;
chPtr - > hz = 1000 ;
chPtr - > gain = 1.0 ;
chPtr - > mn = mn ;
chPtr - > m = cmMemAllocZ ( cmApSample_t , mn ) ;
chPtr - > mi = 0 ;
2020-02-29 17:31:01 +00:00
2012-10-30 03:52:39 +00:00
}
void _cmApIoFinalize ( cmApIO * ioPtr )
{
unsigned i ;
for ( i = 0 ; i < ioPtr - > chCnt ; + + i )
_cmApChFinalize ( ioPtr - > chArray + i ) ;
cmMemPtrFree ( & ioPtr - > chArray ) ;
ioPtr - > chCnt = 0 ;
ioPtr - > n = 0 ;
}
2020-02-29 17:31:01 +00:00
void _cmApIoInitialize ( cmApIO * ioPtr , double srate , unsigned framesPerCycle , unsigned chCnt , unsigned n , unsigned meterBufN , unsigned dspFrameCnt , int srateMult )
2012-10-30 03:52:39 +00:00
{
unsigned i ;
2020-02-29 17:31:01 +00:00
if ( srateMult = = 0 )
srateMult = 1 ;
2012-10-30 03:52:39 +00:00
_cmApIoFinalize ( ioPtr ) ;
n + = ( n % dspFrameCnt ) ; // force buffer size to be a multiple of dspFrameCnt
2013-12-15 23:28:11 +00:00
ioPtr - > chArray = chCnt = = 0 ? NULL : cmMemAllocZ ( cmApCh , chCnt ) ;
ioPtr - > chCnt = chCnt ;
2020-02-29 17:31:01 +00:00
ioPtr - > n = srateMult < 0 ? n : n * srateMult ;
2013-12-15 23:28:11 +00:00
ioPtr - > faultCnt = 0 ;
ioPtr - > framesPerCycle = framesPerCycle ;
ioPtr - > srate = srate ;
2020-02-29 17:31:01 +00:00
ioPtr - > srateMult = srateMult ;
2013-12-15 23:28:11 +00:00
ioPtr - > dspFrameCnt = dspFrameCnt ;
ioPtr - > timeStamp . tv_sec = 0 ;
ioPtr - > timeStamp . tv_nsec = 0 ;
ioPtr - > ioFrameCnt = 0 ;
2012-10-30 03:52:39 +00:00
for ( i = 0 ; i < chCnt ; + + i )
2020-02-29 17:31:01 +00:00
_cmApChInitialize ( ioPtr - > chArray + i , ioPtr - > n , meterBufN ) ;
2012-10-30 03:52:39 +00:00
}
void _cmApDevFinalize ( cmApDev * dp )
{
unsigned i ;
for ( i = 0 ; i < kIoApCnt ; + + i )
_cmApIoFinalize ( dp - > ioArray + i ) ;
}
2020-02-29 17:31:01 +00:00
void _cmApDevInitialize ( cmApDev * dp , double srate , unsigned iFpC , unsigned iChCnt , unsigned iBufN , unsigned oFpC , unsigned oChCnt , unsigned oBufN , unsigned meterBufN , unsigned dspFrameCnt , int srateMult )
2012-10-30 03:52:39 +00:00
{
unsigned i ;
_cmApDevFinalize ( dp ) ;
for ( i = 0 ; i < kIoApCnt ; + + i )
{
2020-02-29 17:31:01 +00:00
unsigned chCnt = i = = kInApIdx ? iChCnt : oChCnt ;
unsigned bufN = i = = kInApIdx ? iBufN : oBufN ;
unsigned fpc = i = = kInApIdx ? iFpC : oFpC ;
_cmApIoInitialize ( dp - > ioArray + i , srate , fpc , chCnt , bufN , meterBufN , dspFrameCnt , srateMult ) ;
2012-10-30 03:52:39 +00:00
}
}
cmAbRC_t cmApBufInitialize ( unsigned devCnt , unsigned meterMs )
{
cmAbRC_t rc ;
if ( ( rc = cmApBufFinalize ( ) ) ! = kOkAbRC )
return rc ;
_cmApBuf . devArray = cmMemAllocZ ( cmApDev , devCnt ) ;
_cmApBuf . devCnt = devCnt ;
2013-04-01 05:13:07 +00:00
cmApBufSetMeterMs ( meterMs ) ;
2020-02-29 17:31:01 +00:00
2012-10-30 03:52:39 +00:00
return kOkAbRC ;
}
cmAbRC_t cmApBufFinalize ( )
{
unsigned i ;
for ( i = 0 ; i < _cmApBuf . devCnt ; + + i )
_cmApDevFinalize ( _cmApBuf . devArray + i ) ;
cmMemPtrFree ( & _cmApBuf . devArray ) ;
cmMemPtrFree ( & _cmApBuf . zeroBuf ) ;
_cmApBuf . devCnt = 0 ;
2020-02-29 17:31:01 +00:00
FILE * fp ;
if ( _cmApBuf . abufIdx > 0 )
{
if ( ( fp = fopen ( " /home/kevin/temp/temp.csv " , " wt " ) ) ! = NULL )
{
int i ;
for ( i = 0 ; i < _cmApBuf . abufIdx ; + + i )
{
fprintf ( fp , " %f, \n " , _cmApBuf . abuf [ i ] ) ;
}
fclose ( fp ) ;
}
}
2012-10-30 03:52:39 +00:00
return kOkAbRC ;
}
cmAbRC_t cmApBufSetup (
unsigned devIdx ,
double srate ,
unsigned dspFrameCnt ,
unsigned bufCnt ,
unsigned inChCnt ,
unsigned inFramesPerCycle ,
unsigned outChCnt ,
2020-02-29 17:31:01 +00:00
unsigned outFramesPerCycle ,
int srateMult )
2012-10-30 03:52:39 +00:00
{
cmApDev * devPtr = _cmApBuf . devArray + devIdx ;
unsigned iBufN = bufCnt * inFramesPerCycle ;
unsigned oBufN = bufCnt * outFramesPerCycle ;
unsigned meterBufN = cmMax ( 1 , floor ( srate * _cmApBuf . meterMs / ( 1000.0 * outFramesPerCycle ) ) ) ;
2020-02-29 17:31:01 +00:00
_cmApDevInitialize ( devPtr , srate , inFramesPerCycle , inChCnt , iBufN , outFramesPerCycle , outChCnt , oBufN , meterBufN , dspFrameCnt , srateMult ) ;
2012-10-30 03:52:39 +00:00
if ( inFramesPerCycle > _cmApBuf . zeroBufCnt | | outFramesPerCycle > _cmApBuf . zeroBufCnt )
{
_cmApBuf . zeroBufCnt = cmMax ( inFramesPerCycle , outFramesPerCycle ) ;
_cmApBuf . zeroBuf = cmMemResizeZ ( cmApSample_t , _cmApBuf . zeroBuf , _cmApBuf . zeroBufCnt ) ;
}
return kOkAbRC ;
}
cmAbRC_t cmApBufPrimeOutput ( unsigned devIdx , unsigned audioCycleCnt )
{
cmApIO * iop = _cmApBuf . devArray [ devIdx ] . ioArray + kOutApIdx ;
unsigned i ;
for ( i = 0 ; i < iop - > chCnt ; + + i )
{
cmApCh * cp = iop - > chArray + i ;
unsigned bn = iop - > n * sizeof ( cmApSample_t ) ;
memset ( cp - > b , 0 , bn ) ;
cp - > oi = 0 ;
cp - > ii = iop - > framesPerCycle * audioCycleCnt ;
cp - > fn = iop - > framesPerCycle * audioCycleCnt ;
}
return kOkAbRC ;
}
2013-12-15 23:28:11 +00:00
void cmApBufOnPortEnable ( unsigned devIdx , bool enableFl )
{
if ( devIdx = = cmInvalidIdx | | enableFl = = false )
return ;
cmApIO * iop = _cmApBuf . devArray [ devIdx ] . ioArray + kOutApIdx ;
iop - > timeStamp . tv_sec = 0 ;
iop - > timeStamp . tv_nsec = 0 ;
iop - > ioFrameCnt = 0 ;
iop = _cmApBuf . devArray [ devIdx ] . ioArray + kInApIdx ;
iop - > timeStamp . tv_sec = 0 ;
iop - > timeStamp . tv_nsec = 0 ;
iop - > ioFrameCnt = 0 ;
}
2012-10-30 03:52:39 +00:00
cmAbRC_t cmApBufUpdate (
cmApAudioPacket_t * inPktArray ,
unsigned inPktCnt ,
cmApAudioPacket_t * outPktArray ,
unsigned outPktCnt )
{
unsigned i , j ;
// copy samples from the packet to the buffer
if ( inPktArray ! = NULL )
{
for ( i = 0 ; i < inPktCnt ; + + i )
{
cmApAudioPacket_t * pp = inPktArray + i ;
cmApIO * ip = _cmApBuf . devArray [ pp - > devIdx ] . ioArray + kInApIdx ; // dest io recd
2013-12-15 23:28:11 +00:00
// if the base time stamp has not yet been set - then set it
if ( ip - > timeStamp . tv_sec = = 0 & & ip - > timeStamp . tv_nsec = = 0 )
ip - > timeStamp = pp - > timeStamp ;
2012-10-30 03:52:39 +00:00
// for each source packet channel and enabled dest channel
for ( j = 0 ; j < pp - > chCnt ; + + j )
{
cmApCh * cp = ip - > chArray + pp - > begChIdx + j ; // dest ch
assert ( pp - > begChIdx + j < ip - > chCnt ) ;
// if the incoming samples would overflow the buffer then ignore them
if ( cp - > fn + pp - > audioFramesCnt > ip - > n )
{
+ + ip - > faultCnt ; // record input overflow
continue ;
}
// if the incoming samples would go off the end of the buffer then
// copy in the samples in two segments (one at the end and another at begin of dest channel)
2020-02-29 17:31:01 +00:00
2012-10-30 03:52:39 +00:00
bool enaFl = cmIsFlag ( cp - > fl , kChApFl ) & & cmIsFlag ( cp - > fl , kMuteApFl ) = = false ;
const cmApSample_t * sp = enaFl ? ( ( cmApSample_t * ) pp - > audioBytesPtr ) + j : _cmApBuf . zeroBuf ;
2020-02-29 17:31:01 +00:00
//unsigned ssn = enaFl ? pp->chCnt : 1; // stride (packet samples are interleaved)
//cmApSample_t* dp = cp->b + cp->ii;
//const cmApSample_t* ep = dp + n0;
2012-10-30 03:52:39 +00:00
// update the meter
if ( cmIsFlag ( cp - > fl , kMeterApFl ) )
{
cp - > m [ cp - > mi ] = _cmApMeter ( sp , pp - > audioFramesCnt , pp - > chCnt ) ;
cp - > mi = ( cp - > mi + 1 ) % cp - > mn ;
}
2020-02-29 17:31:01 +00:00
unsigned incrSmpN = 0 ;
2012-10-30 03:52:39 +00:00
// if the test tone is enabled on this input channel
if ( enaFl & & cmIsFlag ( cp - > fl , kToneApFl ) )
{
2020-02-29 17:31:01 +00:00
//_cmApSine(cp, dp, n0, cp->b, n1, 1, ip->srate );
incrSmpN = _cmApSine ( cp , cp - > b , ip - > n , cp - > ii , 1 , pp - > audioFramesCnt , ip - > srateMult , ip - > srate , cp - > gain ) ;
2012-10-30 03:52:39 +00:00
}
else // otherwise copy samples from the packet to the buffer
{
2020-02-29 17:31:01 +00:00
unsigned pi = cp - > ii ;
cp - > ii = _cmApCopyInSamples ( ( cmApSample_t * ) pp - > audioBytesPtr , pp - > audioFramesCnt , pp - > chCnt , j , cp - > b , ip - > n , cp - > ii , ip - > srateMult , cp - > gain , & cp - > s0 ) ;
if ( false )
if ( j = = 2 & & _cmApBuf . abufIdx < 16384 )
{
int ii ;
for ( ii = pi ; ii ! = cp - > ii & & _cmApBuf . abufIdx < 16384 ; _cmApBuf . abufIdx + + )
{
_cmApBuf . abuf [ _cmApBuf . abufIdx ] = cp - > b [ ii ] ;
ii = ( ii + 1 ) % ip - > n ;
}
}
incrSmpN = cp - > ii > pi ? cp - > ii - pi : ( ip - > n - pi ) + cp - > ii ;
2012-10-30 03:52:39 +00:00
}
2020-02-29 17:31:01 +00:00
cmThUIntIncr ( & cp - > fn , incrSmpN ) ;
2012-10-30 03:52:39 +00:00
}
}
}
// copy samples from the buffer to the packet
if ( outPktArray ! = NULL )
{
for ( i = 0 ; i < outPktCnt ; + + i )
{
cmApAudioPacket_t * pp = outPktArray + i ;
cmApIO * op = _cmApBuf . devArray [ pp - > devIdx ] . ioArray + kOutApIdx ; // dest io recd
2013-12-15 23:28:11 +00:00
// if the base timestamp has not yet been set then set it.
if ( op - > timeStamp . tv_sec = = 0 & & op - > timeStamp . tv_nsec = = 0 )
op - > timeStamp = pp - > timeStamp ;
2012-10-30 03:52:39 +00:00
// for each dest packet channel and enabled source channel
for ( j = 0 ; j < pp - > chCnt ; + + j )
{
cmApCh * cp = op - > chArray + pp - > begChIdx + j ; // dest ch
unsigned n0 = op - > n - cp - > oi ; // first src segment
unsigned n1 = 0 ; // second src segment
volatile unsigned fn = cp - > fn ; // store fn because it may be changed by the client thread
// if the outgoing samples will underflow the buffer
if ( pp - > audioFramesCnt > fn )
{
+ + op - > faultCnt ; // record an output underflow
// if the buffer is empty - zero the packet and return
if ( fn = = 0 )
{
memset ( pp - > audioBytesPtr , 0 , pp - > audioFramesCnt * sizeof ( cmApSample_t ) ) ;
continue ;
}
// ... otherwise decrease the count of returned samples
pp - > audioFramesCnt = fn ;
}
// if the outgong segments would go off the end of the buffer then
// arrange to wrap to the begining of the buffer
if ( n0 < pp - > audioFramesCnt )
n1 = pp - > audioFramesCnt - n0 ;
else
n0 = pp - > audioFramesCnt ;
2020-02-29 17:31:01 +00:00
cmApSample_t * bpp = ( ( cmApSample_t * ) pp - > audioBytesPtr ) + j ;
cmApSample_t * dp = bpp ;
2012-10-30 03:52:39 +00:00
bool enaFl = cmIsFlag ( cp - > fl , kChApFl ) & & cmIsFlag ( cp - > fl , kMuteApFl ) = = false ;
2020-02-29 17:31:01 +00:00
unsigned decrSmpN = 0 ;
2012-10-30 03:52:39 +00:00
// if the tone is enabled on this channel
if ( enaFl & & cmIsFlag ( cp - > fl , kToneApFl ) )
{
2020-02-29 17:31:01 +00:00
//_cmApSine(cp, dp, n0, dp + n0*pp->chCnt, n1, pp->chCnt, op->srate );
decrSmpN = _cmApSine ( cp , ( cmApSample_t * ) pp - > audioBytesPtr , pp - > audioFramesCnt , 0 , pp - > chCnt , pp - > audioFramesCnt , op - > srateMult , op - > srate , cp - > gain ) ;
2012-10-30 03:52:39 +00:00
}
else // otherwise copy samples from the output buffer to the packet
{
const cmApSample_t * sp = enaFl ? cp - > b + cp - > oi : _cmApBuf . zeroBuf ;
const cmApSample_t * ep = sp + n0 ;
2020-02-29 17:31:01 +00:00
unsigned pi = cp - > oi ;
cp - > oi = _cmApCopyOutSamples ( enaFl ? cp - > b : _cmApBuf . zeroBuf , op - > n , cp - > oi , ( cmApSample_t * ) pp - > audioBytesPtr , pp - > audioFramesCnt , pp - > chCnt , j , op - > srateMult , cp - > gain , & cp - > s0 ) ;
decrSmpN = cp - > oi > pi ? cp - > oi - pi : ( op - > n - pi ) + cp - > oi ;
if ( true )
if ( j = = 2 & & _cmApBuf . abufIdx < 16384 )
{
int ii ;
for ( ii = pi ; ii ! = cp - > oi & & _cmApBuf . abufIdx < 16384 ; _cmApBuf . abufIdx + + )
{
_cmApBuf . abuf [ _cmApBuf . abufIdx ] = cp - > b [ ii ] ;
ii = ( ii + 1 ) % op - > n ;
}
}
/*
2012-10-30 03:52:39 +00:00
// copy the first segment
for ( ; sp < ep ; dp + = pp - > chCnt )
* dp = cp - > gain * * sp + + ;
// if there is a second segment
if ( n1 > 0 )
{
// copy the second segment
sp = enaFl ? cp - > b : _cmApBuf . zeroBuf ;
ep = sp + n1 ;
for ( ; sp < ep ; dp + = pp - > chCnt )
* dp = cp - > gain * * sp + + ;
}
2020-02-29 17:31:01 +00:00
*/
2012-10-30 03:52:39 +00:00
}
// update the meter
if ( cmIsFlag ( cp - > fl , kMeterApFl ) )
{
cp - > m [ cp - > mi ] = _cmApMeter ( ( ( cmApSample_t * ) pp - > audioBytesPtr ) + j , pp - > audioFramesCnt , pp - > chCnt ) ;
cp - > mi = ( cp - > mi + 1 ) % cp - > mn ;
}
// advance the output channel buffer
2020-02-29 17:31:01 +00:00
/*
2012-10-30 03:52:39 +00:00
cp - > oi = n1 > 0 ? n1 : cp - > oi + n0 ;
cmThUIntDecr ( & cp - > fn , pp - > audioFramesCnt ) ;
2020-02-29 17:31:01 +00:00
*/
//cp->fn -= pp->audioFramesCnt;
cmThUIntDecr ( & cp - > fn , decrSmpN ) ;
2012-10-30 03:52:39 +00:00
}
}
}
return kOkAbRC ;
}
unsigned cmApBufMeterMs ( )
{ return _cmApBuf . meterMs ; }
2013-04-01 05:13:07 +00:00
void cmApBufSetMeterMs ( unsigned meterMs )
{
_cmApBuf . meterMs = cmMin ( 1000 , cmMax ( 10 , meterMs ) ) ;
}
2012-10-30 03:52:39 +00:00
unsigned cmApBufChannelCount ( unsigned devIdx , unsigned flags )
{
if ( devIdx = = cmInvalidIdx )
return 0 ;
unsigned idx = flags & kInApFl ? kInApIdx : kOutApIdx ;
return _cmApBuf . devArray [ devIdx ] . ioArray [ idx ] . chCnt ;
}
void cmApBufSetFlag ( unsigned devIdx , unsigned chIdx , unsigned flags )
{
if ( devIdx = = cmInvalidIdx )
return ;
unsigned idx = flags & kInApFl ? kInApIdx : kOutApIdx ;
bool enableFl = flags & kEnableApFl ? true : false ;
unsigned i = chIdx ! = - 1 ? chIdx : 0 ;
unsigned n = chIdx ! = - 1 ? chIdx + 1 : _cmApBuf . devArray [ devIdx ] . ioArray [ idx ] . chCnt ;
for ( ; i < n ; + + i )
{
cmApCh * cp = _cmApBuf . devArray [ devIdx ] . ioArray [ idx ] . chArray + i ;
cp - > fl = cmEnaFlag ( cp - > fl , flags & ( kChApFl | kToneApFl | kMeterApFl | kMuteApFl | kPassApFl ) , enableFl ) ;
}
}
bool cmApBufIsFlag ( unsigned devIdx , unsigned chIdx , unsigned flags )
{
if ( devIdx = = cmInvalidIdx )
return false ;
unsigned idx = flags & kInApFl ? kInApIdx : kOutApIdx ;
return cmIsFlag ( _cmApBuf . devArray [ devIdx ] . ioArray [ idx ] . chArray [ chIdx ] . fl , flags ) ;
}
void cmApBufEnableChannel ( unsigned devIdx , unsigned chIdx , unsigned flags )
{ cmApBufSetFlag ( devIdx , chIdx , flags | kChApFl ) ; }
bool cmApBufIsChannelEnabled ( unsigned devIdx , unsigned chIdx , unsigned flags )
{ return cmApBufIsFlag ( devIdx , chIdx , flags | kChApFl ) ; }
void cmApBufEnableTone ( unsigned devIdx , unsigned chIdx , unsigned flags )
{ cmApBufSetFlag ( devIdx , chIdx , flags | kToneApFl ) ; }
bool cmApBufIsToneEnabled ( unsigned devIdx , unsigned chIdx , unsigned flags )
{ return cmApBufIsFlag ( devIdx , chIdx , flags | kToneApFl ) ; }
void cmApBufEnableMute ( unsigned devIdx , unsigned chIdx , unsigned flags )
{ cmApBufSetFlag ( devIdx , chIdx , flags | kMuteApFl ) ; }
bool cmApBufIsMuteEnabled ( unsigned devIdx , unsigned chIdx , unsigned flags )
{ return cmApBufIsFlag ( devIdx , chIdx , flags | kMuteApFl ) ; }
void cmApBufEnablePass ( unsigned devIdx , unsigned chIdx , unsigned flags )
{ cmApBufSetFlag ( devIdx , chIdx , flags | kPassApFl ) ; }
bool cmApBufIsPassEnabled ( unsigned devIdx , unsigned chIdx , unsigned flags )
{ return cmApBufIsFlag ( devIdx , chIdx , flags | kPassApFl ) ; }
void cmApBufEnableMeter ( unsigned devIdx , unsigned chIdx , unsigned flags )
{ cmApBufSetFlag ( devIdx , chIdx , flags | kMeterApFl ) ; }
bool cmApBufIsMeterEnabled ( unsigned devIdx , unsigned chIdx , unsigned flags )
{ return cmApBufIsFlag ( devIdx , chIdx , flags | kMeterApFl ) ; }
cmApSample_t cmApBufMeter ( unsigned devIdx , unsigned chIdx , unsigned flags )
{
if ( devIdx = = cmInvalidIdx )
return 0 ;
unsigned idx = flags & kInApFl ? kInApIdx : kOutApIdx ;
const cmApCh * cp = _cmApBuf . devArray [ devIdx ] . ioArray [ idx ] . chArray + chIdx ;
return _cmApMeterValue ( cp ) ;
}
void cmApBufSetGain ( unsigned devIdx , unsigned chIdx , unsigned flags , double gain )
{
if ( devIdx = = cmInvalidIdx )
return ;
unsigned idx = flags & kInApFl ? kInApIdx : kOutApIdx ;
unsigned i = chIdx ! = - 1 ? chIdx : 0 ;
unsigned n = i + ( chIdx ! = - 1 ? 1 : _cmApBuf . devArray [ devIdx ] . ioArray [ idx ] . chCnt ) ;
for ( ; i < n ; + + i )
_cmApBuf . devArray [ devIdx ] . ioArray [ idx ] . chArray [ i ] . gain = gain ;
}
double cmApBufGain ( unsigned devIdx , unsigned chIdx , unsigned flags )
{
if ( devIdx = = cmInvalidIdx )
return 0 ;
unsigned idx = flags & kInApFl ? kInApIdx : kOutApIdx ;
return _cmApBuf . devArray [ devIdx ] . ioArray [ idx ] . chArray [ chIdx ] . gain ;
}
unsigned cmApBufGetStatus ( unsigned devIdx , unsigned flags , double * meterArray , unsigned meterCnt , unsigned * faultCntPtr )
{
if ( devIdx = = cmInvalidIdx )
return 0 ;
unsigned ioIdx = cmIsFlag ( flags , kInApFl ) ? kInApIdx : kOutApIdx ;
cmApIO * iop = _cmApBuf . devArray [ devIdx ] . ioArray + ioIdx ;
unsigned chCnt = cmMin ( iop - > chCnt , meterCnt ) ;
unsigned i ;
if ( faultCntPtr ! = NULL )
* faultCntPtr = iop - > faultCnt ;
for ( i = 0 ; i < chCnt ; + + i )
meterArray [ i ] = _cmApMeterValue ( iop - > chArray + i ) ;
return chCnt ;
}
bool cmApBufIsDeviceReady ( unsigned devIdx , unsigned flags )
{
//bool iFl = true;
//bool oFl = true;
unsigned i = 0 ;
if ( devIdx = = cmInvalidIdx )
return false ;
if ( flags & kInApFl )
{
const cmApIO * ioPtr = _cmApBuf . devArray [ devIdx ] . ioArray + kInApIdx ;
for ( i = 0 ; i < ioPtr - > chCnt ; + + i )
if ( ioPtr - > chArray [ i ] . fn < ioPtr - > dspFrameCnt )
return false ;
//iFl = ioPtr->fn > ioPtr->dspFrameCnt;
}
if ( flags & kOutApFl )
{
const cmApIO * ioPtr = _cmApBuf . devArray [ devIdx ] . ioArray + kOutApIdx ;
for ( i = 0 ; i < ioPtr - > chCnt ; + + i )
if ( ( ioPtr - > n - ioPtr - > chArray [ i ] . fn ) < ioPtr - > dspFrameCnt )
return false ;
//oFl = (ioPtr->n - ioPtr->fn) > ioPtr->dspFrameCnt;
}
return true ;
//return iFl & oFl;
}
// Note that his function returns audio samples but does NOT
// change any internal states.
void cmApBufGet ( unsigned devIdx , unsigned flags , cmApSample_t * bufArray [ ] , unsigned bufChCnt )
{
unsigned i ;
if ( devIdx = = cmInvalidIdx )
{
for ( i = 0 ; i < bufChCnt ; + + i )
bufArray [ i ] = NULL ;
return ;
}
unsigned idx = flags & kInApFl ? kInApIdx : kOutApIdx ;
const cmApIO * ioPtr = _cmApBuf . devArray [ devIdx ] . ioArray + idx ;
unsigned n = bufChCnt < ioPtr - > chCnt ? bufChCnt : ioPtr - > chCnt ;
cmApCh * cp = ioPtr - > chArray ;
for ( i = 0 ; i < n ; + + i , + + cp )
{
unsigned offs = flags & kInApFl ? cp - > oi : cp - > ii ;
bufArray [ i ] = cmIsFlag ( cp - > fl , kChApFl ) ? cp - > b + offs : NULL ;
}
}
2013-12-15 23:28:11 +00:00
void _cmApBufCalcTimeStamp ( double srate , const cmTimeSpec_t * baseTimeStamp , unsigned frmCnt , cmTimeSpec_t * retTimeStamp )
{
if ( retTimeStamp = = NULL )
return ;
double secs = frmCnt / srate ;
unsigned int_secs = floor ( secs ) ;
double frac_secs = secs - int_secs ;
retTimeStamp - > tv_nsec = floor ( baseTimeStamp - > tv_nsec + frac_secs * 1000000000 ) ;
retTimeStamp - > tv_sec = baseTimeStamp - > tv_sec + int_secs ;
if ( retTimeStamp - > tv_nsec > 1000000000 )
{
retTimeStamp - > tv_nsec - = 1000000000 ;
retTimeStamp - > tv_sec + = 1 ;
}
}
void cmApBufGetIO ( unsigned iDevIdx , cmApSample_t * iBufArray [ ] , unsigned iBufChCnt , cmTimeSpec_t * iTimeStampPtr , unsigned oDevIdx , cmApSample_t * oBufArray [ ] , unsigned oBufChCnt , cmTimeSpec_t * oTimeStampPtr )
2012-10-30 03:52:39 +00:00
{
cmApBufGet ( iDevIdx , kInApFl , iBufArray , iBufChCnt ) ;
cmApBufGet ( oDevIdx , kOutApFl , oBufArray , oBufChCnt ) ;
unsigned i = 0 ;
if ( iDevIdx ! = cmInvalidIdx & & oDevIdx ! = cmInvalidIdx )
{
const cmApIO * ip = _cmApBuf . devArray [ iDevIdx ] . ioArray + kInApIdx ;
const cmApIO * op = _cmApBuf . devArray [ oDevIdx ] . ioArray + kOutApIdx ;
unsigned minChCnt = cmMin ( iBufChCnt , oBufChCnt ) ;
unsigned frmCnt = cmMin ( ip - > dspFrameCnt , op - > dspFrameCnt ) ;
unsigned byteCnt = frmCnt * sizeof ( cmApSample_t ) ;
2013-12-15 23:28:11 +00:00
_cmApBufCalcTimeStamp ( ip - > srate , & ip - > timeStamp , ip - > ioFrameCnt , iTimeStampPtr ) ;
_cmApBufCalcTimeStamp ( op - > srate , & op - > timeStamp , op - > ioFrameCnt , oTimeStampPtr ) ;
2012-10-30 03:52:39 +00:00
for ( i = 0 ; i < minChCnt ; + + i )
{
cmApCh * ocp = op - > chArray + i ;
cmApCh * icp = ip - > chArray + i ;
if ( oBufArray [ i ] ! = NULL )
{
// if either the input or output channel is marked for pass-through
if ( cmAllFlags ( ocp - > fl , kPassApFl ) | | cmAllFlags ( icp - > fl , kPassApFl ) )
{
memcpy ( oBufArray [ i ] , iBufArray [ i ] , byteCnt ) ;
// set the output buffer to NULL to prevent it being over written by the client
oBufArray [ i ] = NULL ;
}
else
{
// zero the output buffer
memset ( oBufArray [ i ] , 0 , byteCnt ) ;
}
}
}
}
if ( oDevIdx ! = cmInvalidIdx )
{
const cmApIO * op = _cmApBuf . devArray [ oDevIdx ] . ioArray + kOutApIdx ;
unsigned byteCnt = op - > dspFrameCnt * sizeof ( cmApSample_t ) ;
2013-12-15 23:28:11 +00:00
_cmApBufCalcTimeStamp ( op - > srate , & op - > timeStamp , op - > ioFrameCnt , oTimeStampPtr ) ;
2012-10-30 03:52:39 +00:00
for ( ; i < oBufChCnt ; + + i )
if ( oBufArray [ i ] ! = NULL )
memset ( oBufArray [ i ] , 0 , byteCnt ) ;
}
}
void cmApBufAdvance ( unsigned devIdx , unsigned flags )
{
unsigned i ;
if ( devIdx = = cmInvalidIdx )
return ;
if ( flags & kInApFl )
{
cmApIO * ioPtr = _cmApBuf . devArray [ devIdx ] . ioArray + kInApIdx ;
for ( i = 0 ; i < ioPtr - > chCnt ; + + i )
{
cmApCh * cp = ioPtr - > chArray + i ;
cp - > oi = ( cp - > oi + ioPtr - > dspFrameCnt ) % ioPtr - > n ;
cmThUIntDecr ( & cp - > fn , ioPtr - > dspFrameCnt ) ;
}
2013-12-15 23:28:11 +00:00
// count the number of samples input from this device
if ( ioPtr - > timeStamp . tv_sec ! = 0 & & ioPtr - > timeStamp . tv_nsec ! = 0 )
cmThUIntIncr ( & ioPtr - > ioFrameCnt , ioPtr - > dspFrameCnt ) ;
2012-10-30 03:52:39 +00:00
}
if ( flags & kOutApFl )
{
cmApIO * ioPtr = _cmApBuf . devArray [ devIdx ] . ioArray + kOutApIdx ;
for ( i = 0 ; i < ioPtr - > chCnt ; + + i )
{
cmApCh * cp = ioPtr - > chArray + i ;
cp - > ii = ( cp - > ii + ioPtr - > dspFrameCnt ) % ioPtr - > n ;
cmThUIntIncr ( & cp - > fn , ioPtr - > dspFrameCnt ) ;
}
2013-12-15 23:28:11 +00:00
// count the number of samples output from this device
if ( ioPtr - > timeStamp . tv_sec ! = 0 & & ioPtr - > timeStamp . tv_nsec ! = 0 )
cmThUIntIncr ( & ioPtr - > ioFrameCnt , ioPtr - > dspFrameCnt ) ;
2012-10-30 03:52:39 +00:00
}
}
void cmApBufInputToOutput ( unsigned iDevIdx , unsigned oDevIdx )
{
if ( iDevIdx = = cmInvalidIdx | | oDevIdx = = cmInvalidIdx )
return ;
unsigned iChCnt = cmApBufChannelCount ( iDevIdx , kInApFl ) ;
unsigned oChCnt = cmApBufChannelCount ( oDevIdx , kOutApFl ) ;
unsigned chCnt = iChCnt < oChCnt ? iChCnt : oChCnt ;
unsigned i ;
cmApSample_t * iBufPtrArray [ iChCnt ] ;
cmApSample_t * oBufPtrArray [ oChCnt ] ;
while ( cmApBufIsDeviceReady ( iDevIdx , kInApFl ) & & cmApBufIsDeviceReady ( oDevIdx , kOutApFl ) )
{
cmApBufGet ( iDevIdx , kInApFl , iBufPtrArray , iChCnt ) ;
cmApBufGet ( oDevIdx , kOutApFl , oBufPtrArray , oChCnt ) ;
// Warning: buffer pointers to disabled channels will be set to NULL
for ( i = 0 ; i < chCnt ; + + i )
{
cmApIO * ip = _cmApBuf . devArray [ iDevIdx ] . ioArray + kInApIdx ;
cmApIO * op = _cmApBuf . devArray [ oDevIdx ] . ioArray + kOutApIdx ;
assert ( ip - > dspFrameCnt = = op - > dspFrameCnt ) ;
unsigned byteCnt = ip - > dspFrameCnt * sizeof ( cmApSample_t ) ;
2020-02-21 20:38:22 +00:00
2012-10-30 03:52:39 +00:00
if ( oBufPtrArray [ i ] ! = NULL )
{
// the input channel is not disabled
if ( iBufPtrArray [ i ] ! = NULL )
memcpy ( oBufPtrArray [ i ] , iBufPtrArray [ i ] , byteCnt ) ;
else
// the input channel is disabled but the output is not - so fill the output with zeros
memset ( oBufPtrArray [ i ] , 0 , byteCnt ) ;
}
}
cmApBufAdvance ( iDevIdx , kInApFl ) ;
cmApBufAdvance ( oDevIdx , kOutApFl ) ;
}
}
void cmApBufReport ( cmRpt_t * rpt )
{
unsigned i , j , k ;
for ( i = 0 ; i < _cmApBuf . devCnt ; + + i )
{
cmRptPrintf ( rpt , " %i " , i ) ;
for ( j = 0 ; j < kIoApCnt ; + + j )
{
cmApIO * ip = _cmApBuf . devArray [ i ] . ioArray + j ;
unsigned ii = 0 ;
unsigned oi = 0 ;
unsigned fn = 0 ;
2020-02-21 20:38:22 +00:00
cmApSample_t mtr = 0 ;
2012-10-30 03:52:39 +00:00
for ( k = 0 ; k < ip - > chCnt ; + + k )
{
cmApCh * cp = ip - > chArray + i ;
ii + = cp - > ii ;
oi + = cp - > oi ;
fn + = cp - > fn ;
2020-02-21 20:38:22 +00:00
mtr + = _cmApMeterValue ( cp ) ;
2012-10-30 03:52:39 +00:00
}
2020-02-21 20:38:22 +00:00
cmRptPrintf ( rpt , " %s - i:%7i o:%7i f:%7i n:%7i err %s:%7i mtr:%5.4f " ,
2012-10-30 03:52:39 +00:00
j = = 0 ? " IN " : " OUT " ,
2020-02-21 20:38:22 +00:00
ii , oi , fn , ip - > n , ( j = = 0 ? " over " : " under " ) , ip - > faultCnt , mtr ) ;
2012-10-30 03:52:39 +00:00
}
cmRptPrintf ( rpt , " \n " ) ;
}
}
/// [cmApBufExample]
void cmApBufTest ( cmRpt_t * rpt )
{
unsigned devIdx = 0 ;
unsigned devCnt = 1 ;
unsigned dspFrameCnt = 10 ;
unsigned cycleCnt = 3 ;
unsigned framesPerCycle = 25 ;
unsigned inChCnt = 2 ;
unsigned outChCnt = inChCnt ;
unsigned sigN = cycleCnt * framesPerCycle * inChCnt ;
double srate = 44100.0 ;
unsigned meterMs = 50 ;
2020-02-29 17:31:01 +00:00
int srateMult = 1 ;
2012-10-30 03:52:39 +00:00
unsigned bufChCnt = inChCnt ;
cmApSample_t * inBufArray [ bufChCnt ] ;
cmApSample_t * outBufArray [ bufChCnt ] ;
cmApSample_t iSig [ sigN ] ;
cmApSample_t oSig [ sigN ] ;
cmApSample_t * os = oSig ;
cmApAudioPacket_t pkt ;
int i , j ;
// create a simulated signal
for ( i = 0 ; i < sigN ; + + i )
{
iSig [ i ] = i ;
oSig [ i ] = 0 ;
}
pkt . devIdx = 0 ;
pkt . begChIdx = 0 ;
pkt . chCnt = inChCnt ;
pkt . audioFramesCnt = framesPerCycle ;
pkt . bitsPerSample = 32 ;
pkt . flags = 0 ;
// initialize a the audio buffer
cmApBufInitialize ( devCnt , meterMs ) ;
// setup the buffer with the specific parameters to by used by the host audio ports
2020-02-29 17:31:01 +00:00
cmApBufSetup ( devIdx , srate , dspFrameCnt , cycleCnt , inChCnt , framesPerCycle , outChCnt , framesPerCycle , srateMult ) ;
2012-10-30 03:52:39 +00:00
// simulate cylcing through sigN buffer transactions
for ( i = 0 ; i < sigN ; i + = framesPerCycle * inChCnt )
{
// setup an incoming audio packet
pkt . audioFramesCnt = framesPerCycle ;
pkt . audioBytesPtr = iSig + i ;
// simulate a call from the audio port with incoming samples
// (fill the audio buffers internal input buffers)
cmApBufUpdate ( & pkt , 1 , NULL , 0 ) ;
// if all devices need to be serviced
while ( cmApBufIsDeviceReady ( devIdx , kInApFl | kOutApFl ) )
{
// get pointers to full internal input buffers
cmApBufGet ( devIdx , kInApFl , inBufArray , bufChCnt ) ;
// get pointers to empty internal output buffers
cmApBufGet ( devIdx , kOutApFl , outBufArray , bufChCnt ) ;
// Warning: pointers to disabled channels will be set to NULL.
// simulate a play through by copying the incoming samples to the outgoing buffers.
for ( j = 0 ; j < bufChCnt ; + + j )
if ( outBufArray [ j ] ! = NULL )
{
// if the input is disabled - but the output is not then zero the output buffer
if ( inBufArray [ j ] = = NULL )
memset ( outBufArray [ j ] , 0 , dspFrameCnt * sizeof ( cmApSample_t ) ) ;
else
// copy the input to the output
memcpy ( outBufArray [ j ] , inBufArray [ j ] , dspFrameCnt * sizeof ( cmApSample_t ) ) ;
}
// signal the buffer that this cycle is complete.
// (marks current internal input/output buffer empty/full)
cmApBufAdvance ( devIdx , kInApFl | kOutApFl ) ;
}
pkt . audioBytesPtr = os ;
// simulate a call from the audio port picking up outgoing samples
// (empties the audio buffers internal output buffers)
cmApBufUpdate ( NULL , 0 , & pkt , 1 ) ;
os + = pkt . audioFramesCnt * pkt . chCnt ;
}
for ( i = 0 ; i < sigN ; + + i )
cmRptPrintf ( rpt , " %f " , oSig [ i ] ) ;
cmRptPrintf ( rpt , " \n " ) ;
cmApBufFinalize ( ) ;
}
/// [cmApBufExample]