cwAudioFile.h/cpp : Add floating point file format.
This commit is contained in:
parent
a511b00493
commit
eed27b2e49
474
cwAudioFile.cpp
474
cwAudioFile.cpp
@ -42,13 +42,28 @@ namespace cw
|
|||||||
kWavChkId = 'EVAW',
|
kWavChkId = 'EVAW',
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { kWriteAudioGutsFl=0x01 };
|
enum
|
||||||
|
{
|
||||||
|
kWriteAudioGutsFl = 0x01,
|
||||||
|
kWriteFloatFl = 0x02
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kIntegerFmtId = 1,
|
||||||
|
kFloatFmtId = 3,
|
||||||
|
kBitsPerByte = 8,
|
||||||
|
|
||||||
|
kMax24Bits = 0x007fffff,
|
||||||
|
kMax16Bits = 0x00007fff,
|
||||||
|
kMax32Bits = 0x7fffffff
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct audiofile_str
|
typedef struct audiofile_str
|
||||||
{
|
{
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
info_t info; // audio file details
|
info_t info; // audio file details
|
||||||
unsigned curFrmIdx; // current frame offset
|
unsigned curFrmIdx; // current frame offset
|
||||||
unsigned fileByteCnt; // file byte cnt
|
unsigned fileByteCnt; // file byte cnt
|
||||||
unsigned smpByteOffs; // byte offset of the first sample
|
unsigned smpByteOffs; // byte offset of the first sample
|
||||||
marker_t* markArray;
|
marker_t* markArray;
|
||||||
@ -373,11 +388,12 @@ namespace cw
|
|||||||
p->info.chCnt = chCnt;
|
p->info.chCnt = chCnt;
|
||||||
p->info.bits = bits;
|
p->info.bits = bits;
|
||||||
p->info.srate = srate;
|
p->info.srate = srate;
|
||||||
|
p->flags = fmtId == kFloatFmtId ? kWriteFloatFl : 0;
|
||||||
|
|
||||||
// if the 'data' chunk was read before the 'fmt' chunk then info.frameCnt
|
// if the 'data' chunk was read before the 'fmt' chunk then info.frameCnt
|
||||||
// holds the number of bytes in the data chunk
|
// holds the number of bytes in the data chunk
|
||||||
if( p->info.frameCnt != 0 )
|
if( p->info.frameCnt != 0 )
|
||||||
p->info.frameCnt = p->info.frameCnt / (p->info.chCnt * p->info.bits/8);
|
p->info.frameCnt = p->info.frameCnt / (p->info.chCnt * (p->info.bits/kBitsPerByte));
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -386,7 +402,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
// if the 'fmt' chunk was read before the 'data' chunk then info.chCnt is non-zero
|
// if the 'fmt' chunk was read before the 'data' chunk then info.chCnt is non-zero
|
||||||
if( p->info.chCnt != 0 )
|
if( p->info.chCnt != 0 )
|
||||||
p->info.frameCnt = chkByteCnt / (p->info.chCnt * p->info.bits/8);
|
p->info.frameCnt = chkByteCnt / (p->info.chCnt * (p->info.bits/kBitsPerByte));
|
||||||
else
|
else
|
||||||
p->info.frameCnt = chkByteCnt;
|
p->info.frameCnt = chkByteCnt;
|
||||||
|
|
||||||
@ -544,7 +560,7 @@ namespace cw
|
|||||||
doubleToX80( p->info.srate, srateX80 );
|
doubleToX80( p->info.srate, srateX80 );
|
||||||
|
|
||||||
unsigned hdrByteCnt = 54;
|
unsigned hdrByteCnt = 54;
|
||||||
unsigned ssndByteCnt = 8 + (p->info.chCnt * p->info.frameCnt * (p->info.bits/8));
|
unsigned ssndByteCnt = 8 + (p->info.chCnt * p->info.frameCnt * (p->info.bits/kBitsPerByte));
|
||||||
unsigned formByteCnt = hdrByteCnt + ssndByteCnt - 8;
|
unsigned formByteCnt = hdrByteCnt + ssndByteCnt - 8;
|
||||||
unsigned commByteCnt = 18;
|
unsigned commByteCnt = 18;
|
||||||
unsigned ssndSmpOffs = 0;
|
unsigned ssndSmpOffs = 0;
|
||||||
@ -583,8 +599,8 @@ namespace cw
|
|||||||
unsigned frmCnt = p->info.frameCnt;
|
unsigned frmCnt = p->info.frameCnt;
|
||||||
short bits = p->info.bits;
|
short bits = p->info.bits;
|
||||||
unsigned srate = p->info.srate;
|
unsigned srate = p->info.srate;
|
||||||
short fmtId = 1;
|
short fmtId = p->flags & kWriteFloatFl ? kFloatFmtId : kIntegerFmtId;
|
||||||
unsigned bytesPerSmp = bits/8;
|
unsigned bytesPerSmp = bits/kBitsPerByte;
|
||||||
unsigned hdrByteCnt = 36;
|
unsigned hdrByteCnt = 36;
|
||||||
unsigned fmtByteCnt = 16;
|
unsigned fmtByteCnt = 16;
|
||||||
unsigned blockAlignCnt = chCnt * bytesPerSmp;
|
unsigned blockAlignCnt = chCnt * bytesPerSmp;
|
||||||
@ -674,13 +690,16 @@ namespace cw
|
|||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
af_t* p = _handleToPtr(h);
|
af_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
//if( p->flags & kWriteFloatFl )
|
||||||
|
// return cwLogError(kOpFailRC,"Conversion from floating point samples to integer output is not implemented.");
|
||||||
|
|
||||||
if( chIdx+chCnt > p->info.chCnt )
|
if( chIdx+chCnt > p->info.chCnt )
|
||||||
return cwLogError(kInvalidArgRC,"Invalid channel index on read. %i > %i",chIdx+chCnt,chCnt);
|
return cwLogError(kInvalidArgRC,"Invalid channel index on read. %i > %i",chIdx+chCnt,chCnt);
|
||||||
|
|
||||||
if( actualFrmCntPtr != NULL )
|
if( actualFrmCntPtr != NULL )
|
||||||
*actualFrmCntPtr = 0;
|
*actualFrmCntPtr = 0;
|
||||||
|
|
||||||
unsigned bps = p->info.bits / 8; // bytes per sample
|
unsigned bps = p->info.bits / kBitsPerByte; // bytes per sample
|
||||||
unsigned bpf = bps * p->info.chCnt; // bytes per file frame
|
unsigned bpf = bps * p->info.chCnt; // bytes per file frame
|
||||||
unsigned bufFrmCnt = std::min(totalFrmCnt,(unsigned)cwAudioFile_MAX_FRAME_READ_CNT);
|
unsigned bufFrmCnt = std::min(totalFrmCnt,(unsigned)cwAudioFile_MAX_FRAME_READ_CNT);
|
||||||
unsigned bytesPerBuf = bufFrmCnt * bpf;
|
unsigned bytesPerBuf = bufFrmCnt * bpf;
|
||||||
@ -842,7 +861,6 @@ namespace cw
|
|||||||
if( actualFrmCntPtr != NULL )
|
if( actualFrmCntPtr != NULL )
|
||||||
*actualFrmCntPtr = 0;
|
*actualFrmCntPtr = 0;
|
||||||
|
|
||||||
|
|
||||||
unsigned totalReadCnt = 0;
|
unsigned totalReadCnt = 0;
|
||||||
unsigned bufFrmCnt = std::min( totalFrmCnt, (unsigned)cwAudioFile_MAX_FRAME_READ_CNT );
|
unsigned bufFrmCnt = std::min( totalFrmCnt, (unsigned)cwAudioFile_MAX_FRAME_READ_CNT );
|
||||||
unsigned bufSmpCnt = bufFrmCnt * chCnt;
|
unsigned bufSmpCnt = bufFrmCnt * chCnt;
|
||||||
@ -877,7 +895,6 @@ namespace cw
|
|||||||
|
|
||||||
if( fbuf != NULL )
|
if( fbuf != NULL )
|
||||||
fPtrBuf[i] = fbuf[i];
|
fPtrBuf[i] = fbuf[i];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -886,61 +903,116 @@ namespace cw
|
|||||||
unsigned actualReadFrmCnt = 0;
|
unsigned actualReadFrmCnt = 0;
|
||||||
frmCnt = std::min( p->info.frameCnt - p->curFrmIdx, std::min( totalFrmCnt-totalReadCnt, bufFrmCnt ) );
|
frmCnt = std::min( p->info.frameCnt - p->curFrmIdx, std::min( totalFrmCnt-totalReadCnt, bufFrmCnt ) );
|
||||||
|
|
||||||
// fill the integer audio buffer from the file
|
// Fill the integer audio buffer from the file.
|
||||||
|
// Note that the input format may be float but this is ok since there size is the same and _readInt() does not processes the values.
|
||||||
if((rc = _readInt( h, frmCnt, chIdx, chCnt, ptrBuf, &actualReadFrmCnt, false )) != kOkRC )
|
if((rc = _readInt( h, frmCnt, chIdx, chCnt, ptrBuf, &actualReadFrmCnt, false )) != kOkRC )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if( actualFrmCntPtr != NULL )
|
if( actualFrmCntPtr != NULL )
|
||||||
*actualFrmCntPtr += actualReadFrmCnt;
|
*actualFrmCntPtr += actualReadFrmCnt;
|
||||||
|
|
||||||
// convert the integer buffer to floating point
|
// Convert the integer buffer to floating point
|
||||||
for(i=0; i<chCnt; ++i)
|
for(i=0; i<chCnt; ++i)
|
||||||
{
|
{
|
||||||
|
|
||||||
int* sp = ptrBuf[i];
|
// if the input is already in float format
|
||||||
|
if( p->flags & kWriteFloatFl )
|
||||||
if( fbuf != NULL )
|
|
||||||
{
|
{
|
||||||
|
float* sp = (float*)ptrBuf[i];
|
||||||
|
|
||||||
float* dp = fPtrBuf[i];
|
// if output is in float (not double) format
|
||||||
float* ep = dp + frmCnt;
|
if( fbuf != NULL )
|
||||||
|
|
||||||
if( sumFl )
|
|
||||||
{
|
{
|
||||||
for(; dp<ep; ++dp,++sp)
|
float* dp = fPtrBuf[i];
|
||||||
*dp += ((float)*sp) / fltMaxSmpVal;
|
float* ep = dp + frmCnt;
|
||||||
|
|
||||||
|
if( sumFl )
|
||||||
|
{
|
||||||
|
for(; dp<ep; ++dp,++sp)
|
||||||
|
*dp += *sp;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(; dp<ep; ++dp,++sp)
|
||||||
|
*dp = *sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( dp <= fbuf[i] + totalFrmCnt );
|
||||||
|
|
||||||
|
fPtrBuf[i] = dp;
|
||||||
|
}
|
||||||
|
else // uf output is in double (not float) format
|
||||||
|
{
|
||||||
|
|
||||||
|
double* dp = dPtrBuf[i];
|
||||||
|
double* ep = dp + frmCnt;
|
||||||
|
|
||||||
|
if( sumFl )
|
||||||
|
{
|
||||||
|
for(; dp<ep; ++dp,++sp)
|
||||||
|
*dp += ((double)*sp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(; dp<ep; ++dp,++sp)
|
||||||
|
*dp = ((double)*sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( dp <= dbuf[i] + totalFrmCnt );
|
||||||
|
dPtrBuf[i] = dp;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
for(; dp<ep; ++dp,++sp)
|
|
||||||
*dp = ((float)*sp) / fltMaxSmpVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert( dp <= fbuf[i] + totalFrmCnt );
|
|
||||||
|
|
||||||
fPtrBuf[i] = dp;
|
|
||||||
}
|
}
|
||||||
else
|
else // if input is an integer format (not float format)
|
||||||
{
|
{
|
||||||
double* dp = dPtrBuf[i];
|
int* sp = ptrBuf[i];
|
||||||
double* ep = dp + frmCnt;
|
|
||||||
|
|
||||||
if( sumFl )
|
// if output is float (not double)
|
||||||
|
if( fbuf != NULL )
|
||||||
{
|
{
|
||||||
for(; dp<ep; ++dp,++sp)
|
|
||||||
*dp += ((double)*sp) / dblMaxSmpVal;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(; dp<ep; ++dp,++sp)
|
|
||||||
*dp = ((double)*sp) / dblMaxSmpVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert( dp <= dbuf[i] + totalFrmCnt );
|
float* dp = fPtrBuf[i];
|
||||||
dPtrBuf[i] = dp;
|
float* ep = dp + frmCnt;
|
||||||
|
|
||||||
|
if( sumFl )
|
||||||
|
{
|
||||||
|
for(; dp<ep; ++dp,++sp)
|
||||||
|
*dp += ((float)*sp) / fltMaxSmpVal;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(; dp<ep; ++dp,++sp)
|
||||||
|
*dp = ((float)*sp) / fltMaxSmpVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( dp <= fbuf[i] + totalFrmCnt );
|
||||||
|
|
||||||
|
fPtrBuf[i] = dp;
|
||||||
|
}
|
||||||
|
else // output is double (not float)
|
||||||
|
{
|
||||||
|
double* dp = dPtrBuf[i];
|
||||||
|
double* ep = dp + frmCnt;
|
||||||
|
|
||||||
|
if( sumFl )
|
||||||
|
{
|
||||||
|
for(; dp<ep; ++dp,++sp)
|
||||||
|
*dp += ((double)*sp) / dblMaxSmpVal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(; dp<ep; ++dp,++sp)
|
||||||
|
*dp = ((double)*sp) / dblMaxSmpVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( dp <= dbuf[i] + totalFrmCnt );
|
||||||
|
dPtrBuf[i] = dp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1011,6 +1083,225 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _write_samples_to_file( af_t* p, unsigned bytesPerSmp, unsigned bufSmpCnt, void* buf )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
if( fwrite( buf, bufSmpCnt*bytesPerSmp, 1, p->fp ) != 1)
|
||||||
|
rc = cwLogError(kWriteFailRC,"Audio file write failed on '%s'.",cwStringNullGuard(p->fn));
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write 8 bit samples
|
||||||
|
//
|
||||||
|
|
||||||
|
// sample writer: int->uint8_t
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const int* sbuf, int8_t* dbuf )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; ++i)
|
||||||
|
dbuf[i] = (((long)sbuf[i]*255) / ((long)INT_MAX - INT_MIN)) + 127;
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sample writer: float->uint8_t
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const float* sbuf, int8_t* dbuf )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; ++i)
|
||||||
|
dbuf[i] = (uint8_t)(sbuf[i] * 128) + 127;
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sample writer: double->uint8_t
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const double* sbuf, int8_t* dbuf )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; ++i)
|
||||||
|
dbuf[i] = (uint8_t)(sbuf[i] * 128) + 127;
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write 16 bit samples
|
||||||
|
//
|
||||||
|
|
||||||
|
// sample writer: int->short
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const int* sbuf, short* dbuf )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; ++i)
|
||||||
|
dbuf[i] = ((long)sbuf[i]*2*SHRT_MAX) / ((long)INT_MAX - INT_MIN);
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sample writer: float->short
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const float* sbuf, short* dbuf )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; ++i)
|
||||||
|
dbuf[i] = (short)(sbuf[i] * SHRT_MAX);
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sample writer: double->short
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const double* sbuf, short* dbuf )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; ++i)
|
||||||
|
dbuf[i] = (short)(sbuf[i] * SHRT_MAX);
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write 24 bit samples
|
||||||
|
//
|
||||||
|
|
||||||
|
inline void int_to_24( int v, uint8_t* d )
|
||||||
|
{
|
||||||
|
uint8_t* s = (uint8_t*)(&v);
|
||||||
|
|
||||||
|
d[0] = s[0];
|
||||||
|
d[1] = s[1];
|
||||||
|
d[2] = s[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// sample writer: int->int24
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const int* sbuf, uint32_t* dbuf )
|
||||||
|
{
|
||||||
|
uint8_t* dbp = (uint8_t*)dbuf;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; dbp+=3, ++i)
|
||||||
|
int_to_24(sbuf[i],dbp);
|
||||||
|
|
||||||
|
return _write_samples_to_file(p,3,bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sample writer: float->int24
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const float* sbuf, uint32_t* dbuf )
|
||||||
|
{
|
||||||
|
uint8_t* dbp = (uint8_t*)dbuf;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; dbp+=3, ++i)
|
||||||
|
{
|
||||||
|
int ismp = sbuf[i]*kMax24Bits;
|
||||||
|
int_to_24(ismp,dbp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sample writer: double->int24
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const double* sbuf, uint32_t* dbuf )
|
||||||
|
{
|
||||||
|
uint8_t* dbp = (uint8_t*)dbuf;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; dbp+=3, ++i)
|
||||||
|
{
|
||||||
|
int ismp = sbuf[i]*kMax24Bits;
|
||||||
|
int_to_24(ismp,dbp);
|
||||||
|
}
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write 32 bit samples
|
||||||
|
//
|
||||||
|
|
||||||
|
// sample writer: int->int
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const int* sbuf, int* dbuf )
|
||||||
|
{
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// float->int
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const float* sbuf, int* dbuf )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; ++i)
|
||||||
|
dbuf[i] = (int)(sbuf[i] * INT_MAX);
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// double->int
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const double* sbuf, int* dbuf )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; ++i)
|
||||||
|
dbuf[i] = (int)(sbuf[i] * INT_MAX);
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write float samples
|
||||||
|
//
|
||||||
|
|
||||||
|
// int->float
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const int* sbuf, float* dbuf )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; ++i)
|
||||||
|
dbuf[i] = sbuf[i]/INT_MAX;
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// float->float
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const float* sbuf, float* dbuf )
|
||||||
|
{
|
||||||
|
memcpy(dbuf,sbuf,bufSmpCnt*sizeof(float));
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// double->float
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const double* sbuf, float* dbuf )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<bufSmpCnt; ++i)
|
||||||
|
dbuf[i] = (float)(sbuf[i]);
|
||||||
|
return _write_samples_to_file(p,sizeof(dbuf[0]),bufSmpCnt,dbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template< typename S, typename D >
|
||||||
|
rc_t _write_samples( af_t* p, unsigned bufSmpCnt, const S* sbuf, D* dbuf)
|
||||||
|
{
|
||||||
|
return cwLogError(kInvalidDataTypeRC,"The source and desintation sample types are not supported by the audio file writer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename S, typename D >
|
||||||
|
rc_t _write_audio( af_t* p, unsigned srcBufFrmCnt, unsigned chCnt, const S* const * srcPtrPtr )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
// Determine the size of the temporary buffer used for deinterleaving, type conversion and file writing
|
||||||
|
unsigned bufFrmCnt = std::min(srcBufFrmCnt,4096u);
|
||||||
|
unsigned bufSmpCnt = bufFrmCnt*chCnt;
|
||||||
|
|
||||||
|
// allocate the temp. buffers
|
||||||
|
S sbuf[ bufSmpCnt ];
|
||||||
|
D dbuf[ bufSmpCnt ];
|
||||||
|
|
||||||
|
// for each frame in the source
|
||||||
|
for(unsigned sfi=0; sfi<srcBufFrmCnt; )
|
||||||
|
{
|
||||||
|
// copy as many samples as are available into the temp. buffer
|
||||||
|
unsigned copyFrmN = std::min( bufFrmCnt, srcBufFrmCnt - sfi );
|
||||||
|
|
||||||
|
// deinterleave the source channel signal arrays into the temp buffer
|
||||||
|
for(unsigned fi=0,si=0; fi<copyFrmN; ++fi)
|
||||||
|
for(unsigned sci=0; sci<chCnt; ++sci,++si)
|
||||||
|
sbuf[si] = srcPtrPtr[sci][sfi+fi];
|
||||||
|
|
||||||
|
// convert the sample data types and write the result to the output file
|
||||||
|
if((rc = _write_samples(p,copyFrmN*chCnt,sbuf,dbuf)) != kOkRC )
|
||||||
|
break;
|
||||||
|
|
||||||
|
p->info.frameCnt += copyFrmN;
|
||||||
|
sfi += copyFrmN;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
rc_t _writeRealSamples( handle_t h, unsigned frmCnt, unsigned chCnt, const void* srcPtrPtr, unsigned realSmpByteCnt )
|
rc_t _writeRealSamples( handle_t h, unsigned frmCnt, unsigned chCnt, const void* srcPtrPtr, unsigned realSmpByteCnt )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
@ -1093,6 +1384,7 @@ namespace cw
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void _test( const char* audioFn )
|
void _test( const char* audioFn )
|
||||||
{
|
{
|
||||||
@ -1181,12 +1473,13 @@ cw::rc_t cw::audiofile::create( handle_t& h, const char* fn, double srate, unsig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
p->fn = mem::duplStr( fn );
|
p->fn = mem::duplStr( fn );
|
||||||
p->info.srate = srate;
|
p->info.srate = srate;
|
||||||
p->info.bits = bits;
|
p->info.bits = bits==0 ? sizeof(float)*kBitsPerByte : bits;
|
||||||
p->info.chCnt = chCnt;
|
p->info.chCnt = chCnt;
|
||||||
p->info.frameCnt = 0;
|
p->info.frameCnt = 0;
|
||||||
p->flags = kWriteAudioGutsFl;
|
p->flags = kWriteAudioGutsFl + (bits==0 ? kWriteFloatFl : 0);
|
||||||
|
|
||||||
// set the swap flags
|
// set the swap flags
|
||||||
bool swapFl = cwIsFlag(p->info.flags,kWavAfFl) ? _cmWavSwapFl : _cmAifSwapFl;
|
bool swapFl = cwIsFlag(p->info.flags,kWavAfFl) ? _cmWavSwapFl : _cmAifSwapFl;
|
||||||
@ -1250,7 +1543,7 @@ cw::rc_t cw::audiofile::seek( handle_t h, unsigned frmIdx )
|
|||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
af_t* p = _handleToPtr(h);
|
af_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
if((rc = _seek(p,p->smpByteOffs + (frmIdx * p->info.chCnt * (p->info.bits/8)), SEEK_SET)) != kOkRC )
|
if((rc = _seek(p,p->smpByteOffs + (frmIdx * p->info.chCnt * (p->info.bits/kBitsPerByte)), SEEK_SET)) != kOkRC )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
p->curFrmIdx = frmIdx;
|
p->curFrmIdx = frmIdx;
|
||||||
@ -1355,11 +1648,11 @@ cw::rc_t cw::audiofile::freeFloatBuf( float** floatBuf, unsigned chCnt )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::audiofile::writeInt( handle_t h, unsigned frmCnt, unsigned chCnt, int** srcPtrPtr )
|
cw::rc_t cw::audiofile::writeInt( handle_t h, unsigned frmCnt, unsigned chCnt, const int* const* srcPtrPtr )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
af_t* p = _handleToPtr(h);
|
af_t* p = _handleToPtr(h);
|
||||||
unsigned bytesPerSmp = p->info.bits / 8;
|
unsigned bytesPerSmp = p->info.bits / kBitsPerByte;
|
||||||
unsigned bufFrmCnt = 1024;
|
unsigned bufFrmCnt = 1024;
|
||||||
unsigned bufByteCnt = bufFrmCnt * bytesPerSmp;
|
unsigned bufByteCnt = bufFrmCnt * bytesPerSmp;
|
||||||
unsigned ci;
|
unsigned ci;
|
||||||
@ -1484,11 +1777,78 @@ cw::rc_t cw::audiofile::writeInt( handle_t h, unsigned frmCnt, unsigned ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cw::rc_t cw::audiofile::writeFloat( handle_t h, unsigned frmCnt, unsigned chCnt, float** bufPtrPtr )
|
cw::rc_t cw::audiofile::writeFloat( handle_t h, unsigned frmCnt, unsigned chCnt, const float* const* srcPtrPtr )
|
||||||
{ return _writeRealSamples(h,frmCnt,chCnt,bufPtrPtr,sizeof(float)); }
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
af_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
cw::rc_t cw::audiofile::writeDouble( handle_t h, unsigned frmCnt, unsigned chCnt, double** bufPtrPtr )
|
if( p->flags & kWriteFloatFl )
|
||||||
{ return _writeRealSamples(h,frmCnt,chCnt,bufPtrPtr,sizeof(double)); }
|
rc = _write_audio<float,float>( p, frmCnt, chCnt, srcPtrPtr );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch(p->info.bits)
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
rc = _write_audio<float,uint8_t>( p, frmCnt, chCnt, srcPtrPtr );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
rc = _write_audio<float,short>( p, frmCnt, chCnt, srcPtrPtr );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 24:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 32:
|
||||||
|
rc = _write_audio<float,int>( p, frmCnt, chCnt, srcPtrPtr );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
cwLogError(kInvalidArgRC,"Invalid bit depth:%i",p->info.bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
//return _writeRealSamples(h,frmCnt,chCnt,bufPtrPtr,sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::audiofile::writeDouble( handle_t h, unsigned frmCnt, unsigned chCnt, const double* const* srcPtrPtr )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
af_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
if( p->flags & kWriteFloatFl )
|
||||||
|
rc = _write_audio<double,float>( p, frmCnt, chCnt, srcPtrPtr );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch(p->info.bits)
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
rc = _write_audio<double,uint8_t>( p, frmCnt, chCnt, srcPtrPtr );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
rc = _write_audio<double,short>( p, frmCnt, chCnt, srcPtrPtr );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 24:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 32:
|
||||||
|
rc = _write_audio<double,int>( p, frmCnt, chCnt, srcPtrPtr );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
cwLogError(kInvalidArgRC,"Invalid bit depth:%i",p->info.bits);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
//return _writeRealSamples(h,frmCnt,chCnt,bufPtrPtr,sizeof(double));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1547,7 +1907,7 @@ cw::rc_t cw::audiofile::minMaxMean( handle_t h, unsigned chIdx, float* minPtr
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::audiofile::writeFileInt( const char* fn, double srate, unsigned bits, unsigned frmCnt, unsigned chCnt, int** bufPtrPtr )
|
cw::rc_t cw::audiofile::writeFileInt( const char* fn, double srate, unsigned bits, unsigned frmCnt, unsigned chCnt, const int* const* bufPtrPtr )
|
||||||
{
|
{
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
handle_t h;
|
handle_t h;
|
||||||
@ -1562,7 +1922,7 @@ cw::rc_t cw::audiofile::writeFileInt( const char* fn, double srate, unsign
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::audiofile::writeFileFloat( const char* fn, double srate, unsigned bits, unsigned frmCnt, unsigned chCnt, float** bufPtrPtr )
|
cw::rc_t cw::audiofile::writeFileFloat( const char* fn, double srate, unsigned bits, unsigned frmCnt, unsigned chCnt, const float* const* bufPtrPtr )
|
||||||
{
|
{
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
handle_t h;
|
handle_t h;
|
||||||
@ -1577,7 +1937,7 @@ cw::rc_t cw::audiofile::writeFileFloat( const char* fn, double srate, unsign
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::audiofile::writeFileDouble( const char* fn, double srate, unsigned bits, unsigned frmCnt, unsigned chCnt, double** bufPtrPtr )
|
cw::rc_t cw::audiofile::writeFileDouble( const char* fn, double srate, unsigned bits, unsigned frmCnt, unsigned chCnt, const double* const* bufPtrPtr )
|
||||||
{
|
{
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
handle_t h;
|
handle_t h;
|
||||||
|
@ -22,7 +22,7 @@ namespace cw
|
|||||||
kWavAfFl = 0x02, // this is a WAV file
|
kWavAfFl = 0x02, // this is a WAV file
|
||||||
kSwapAfFl = 0x04, // file header bytes must be swapped
|
kSwapAfFl = 0x04, // file header bytes must be swapped
|
||||||
kAifcAfFl = 0x08, // this is an AIFC file
|
kAifcAfFl = 0x08, // this is an AIFC file
|
||||||
kSwapSamplesAfFl = 0x10 // file sample bytes must be swapped
|
kSwapSamplesAfFl = 0x10, // file sample bytes must be swapped
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -76,6 +76,7 @@ namespace cw
|
|||||||
|
|
||||||
rc_t open( handle_t& h, const char* fn, info_t* info );
|
rc_t open( handle_t& h, const char* fn, info_t* info );
|
||||||
|
|
||||||
|
// Set bits to 0 to write the file in IEEE float format.
|
||||||
rc_t create( handle_t& h, const char* fn, double srate, unsigned bits, unsigned chN );
|
rc_t create( handle_t& h, const char* fn, double srate, unsigned bits, unsigned chN );
|
||||||
|
|
||||||
rc_t close( handle_t& h );
|
rc_t close( handle_t& h );
|
||||||
@ -134,13 +135,15 @@ namespace cw
|
|||||||
rc_t freeFloatBuf( float** floatBufRef, unsigned chCnt );
|
rc_t freeFloatBuf( float** floatBufRef, unsigned chCnt );
|
||||||
|
|
||||||
// Sample Writing Functions
|
// Sample Writing Functions
|
||||||
rc_t writeInt( handle_t h, unsigned frmCnt, unsigned chCnt, int** bufPtrPtr );
|
rc_t writeInt( handle_t h, unsigned frmCnt, unsigned chCnt, const int* const* bufPtrPtr );
|
||||||
rc_t writeFloat( handle_t h, unsigned frmCnt, unsigned chCnt, float** bufPtrPtr );
|
rc_t writeFloat( handle_t h, unsigned frmCnt, unsigned chCnt, const float* const* bufPtrPtr );
|
||||||
rc_t writeDouble( handle_t h, unsigned frmCnt, unsigned chCnt, double** bufPtrPtr );
|
rc_t writeDouble( handle_t h, unsigned frmCnt, unsigned chCnt, const double* const* bufPtrPtr );
|
||||||
|
|
||||||
rc_t writeFileInt( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, int** bufPtrPtr);
|
// File Writing Functions
|
||||||
rc_t writeFileFloat( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, float** bufPtrPtr);
|
// Set 'bit' to 0 to write the file in IEEE float format.
|
||||||
rc_t writeFileDouble( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, double** bufPtrPtr);
|
rc_t writeFileInt( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, const int* const * bufPtrPtr);
|
||||||
|
rc_t writeFileFloat( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, const float* const* bufPtrPtr);
|
||||||
|
rc_t writeFileDouble( const char* fn, double srate, unsigned bit, unsigned frmCnt, unsigned chCnt, const double* const* bufPtrPtr);
|
||||||
|
|
||||||
|
|
||||||
// Scan an entire audio file and return the minimum, maximum and mean sample value.
|
// Scan an entire audio file and return the minimum, maximum and mean sample value.
|
||||||
|
Loading…
Reference in New Issue
Block a user