Changed audio system to use external driver modules.

This commit is contained in:
kpl 2019-12-25 21:44:14 -05:00
parent d6e0f5e675
commit 85954c5498
19 changed files with 1172 additions and 1442 deletions

View File

@ -17,8 +17,8 @@ SRC += cwSerialPort.cpp cwSerialPortSrv.cpp
HDR += cwMidi.h cwMidiPort.h
SRC += cwMidi.cpp cwMidiPort.cpp cwMidiAlsa.cpp
HDR += cwAudioBuf.h cwAudioPort.h cwAudioPortAlsa.h
SRC += cwAudioBuf.cpp cwAudioPort.cpp cwAudioPortAlsa.cpp
HDR += cwAudioBuf.h cwAudioDevice.h cwAudioDeviceAlsa.h
SRC += cwAudioBuf.cpp cwAudioDevice.cpp cwAudioDeviceAlsa.cpp cwAudioDeviceTest.cpp
LIBS = -lpthread -lwebsockets -lasound

View File

@ -4,7 +4,7 @@
#include "cwMem.h"
#include "cwTime.h"
#include "cwTextBuf.h"
#include "cwAudioPort.h"
#include "cwAudioDevice.h"
#include "cwAudioBuf.h"
/*
@ -853,13 +853,11 @@ void cw::audio::buf::inputToOutput( unsigned iDevIdx, unsigned oDevIdx )
}
void cw::audio::buf::report( textBuf::handle_t tbH )
void cw::audio::buf::report()
{
unsigned i,j,k;
for(i=0; i<_theBuf.devCnt; ++i)
{
textBuf::print(tbH,"%i ",i);
for(j=0; j<kIoApCnt; ++j)
{
cmApIO* ip = _theBuf.devArray[i].ioArray + j;
@ -875,13 +873,11 @@ void cw::audio::buf::report( textBuf::handle_t tbH )
fn += cp->fn;
}
textBuf::print(tbH,"%s - i:%7i o:%7i f:%7i n:%7i err %s:%7i ",
j==0?"IN":"OUT",
cwLogInfo("%i : %s - i:%7i o:%7i f:%7i n:%7i err %s:%7i ",
i,j==0?"IN ":"OUT",
ii,oi,fn,ip->n, (j==0?"over":"under"), ip->faultCnt);
}
textBuf::print(tbH,"\n");
}
}

View File

@ -227,7 +227,7 @@ namespace cw
void inputToOutput( unsigned inDevIdx, unsigned outDevIdx );
// Print the current buffer state.
void report( textBuf::handle_t tbH );
void report();
// Run a buffer usage simulation to test the class. cmAudioPortTest.c calls this function.
void test();

217
cwAudioDevice.cpp Normal file
View File

@ -0,0 +1,217 @@
#include "cwCommon.h"
#include "cwLog.h"
#include "cwCommonImpl.h"
#include "cwMem.h"
#include "cwTime.h"
#include "cwAudioDevice.h"
#include "cwText.h"
namespace cw
{
namespace audio
{
namespace device
{
typedef struct drv_str
{
unsigned begIdx;
unsigned endIdx;
driver_t* drv;
struct drv_str* link;
} drv_t;
typedef struct device_str
{
drv_t* drvList = nullptr;
unsigned nextDrvIdx = 0;
} device_t;
inline device_t* _handleToPtr( handle_t h ){ return handleToPtr<handle_t,device_t>(h); }
cw::rc_t _destroy( device_t* p )
{
drv_t* d = p->drvList;
while( d != nullptr )
{
drv_t* d0 = d->link;
memRelease(d);
d = d0;
}
memRelease(p);
return kOkRC;
}
drv_t* _indexToDriver( device_t* p, unsigned idx )
{
drv_t* l = p->drvList;
for(; l != nullptr; l=l->link )
if( l->begIdx <= idx && idx <= l->endIdx )
return l;
cwLogError(kInvalidArgRC,"An invalid audio device index (%) was requested.",idx);
return nullptr;
}
drv_t* _indexToDriver( handle_t h, unsigned idx )
{
device_t* p = _handleToPtr(h);
return _indexToDriver(p,idx);
}
}
}
}
cw::rc_t cw::audio::device::create( handle_t& hRef )
{
rc_t rc;
if((rc = destroy(hRef)) != kOkRC)
return rc;
device_t* p = memAllocZ<device_t>();
hRef.set(p);
return rc;
}
cw::rc_t cw::audio::device::destroy( handle_t& hRef )
{
rc_t rc = kOkRC;
if( !hRef.isValid() )
return rc;
device_t* p = _handleToPtr(hRef);
if((rc = _destroy(p)) != kOkRC )
return rc;
hRef.clear();
return rc;
}
cw::rc_t cw::audio::device::registerDriver( handle_t h, driver_t* drv )
{
device_t* p = _handleToPtr(h);
unsigned n = drv->deviceCount( drv );
if( n > 0 )
{
drv_t* d = memAllocZ<drv_t>();
d->begIdx = p->nextDrvIdx;
p->nextDrvIdx += n;
d->endIdx = p->nextDrvIdx-1;
d->drv = drv;
d->link = p->drvList;
p->drvList = d;
}
return kOkRC;
}
unsigned cw::audio::device::deviceCount( handle_t h )
{
device_t* p = _handleToPtr(h);
return p->nextDrvIdx;
}
unsigned cw::audio::device::deviceLabelToIndex( handle_t h, const char* label )
{
unsigned n = deviceCount(h);
unsigned i;
for(i=0; i<n; ++i)
{
const char* s = deviceLabel(h,i);
if( textCompare(s,label)==0)
return i;
}
return kInvalidIdx;
}
const char* cw::audio::device::deviceLabel( handle_t h, unsigned devIdx )
{
drv_t* d;
if((d = _indexToDriver(h,devIdx)) != nullptr )
return d->drv->deviceLabel( d->drv, devIdx - d->begIdx );
return nullptr;
}
unsigned cw::audio::device::deviceChannelCount( handle_t h, unsigned devIdx, bool inputFl )
{
drv_t* d;
if((d = _indexToDriver(h,devIdx)) != nullptr )
return d->drv->deviceChannelCount( d->drv, devIdx - d->begIdx, inputFl );
return 0;
}
double cw::audio::device::deviceSampleRate( handle_t h, unsigned devIdx )
{
drv_t* d;
if((d = _indexToDriver(h,devIdx)) != nullptr )
return d->drv->deviceSampleRate( d->drv, devIdx - d->begIdx );
return 0;
}
unsigned cw::audio::device::deviceFramesPerCycle( handle_t h, unsigned devIdx, bool inputFl )
{
drv_t* d;
if((d = _indexToDriver(h,devIdx)) != nullptr )
return d->drv->deviceFramesPerCycle( d->drv, devIdx - d->begIdx, inputFl );
return 0;
}
cw::rc_t cw::audio::device::deviceSetup( handle_t h, unsigned devIdx, double sr, unsigned frmPerCycle, cbFunc_t cb, void* cbData )
{
drv_t* d;
if((d = _indexToDriver(h,devIdx)) != nullptr )
return d->drv->deviceSetup( d->drv, devIdx - d->begIdx, sr, frmPerCycle, cb, cbData );
return kInvalidArgRC;
}
cw::rc_t cw::audio::device::deviceStart( handle_t h, unsigned devIdx )
{
drv_t* d;
if((d = _indexToDriver(h,devIdx)) != nullptr )
return d->drv->deviceStart( d->drv, devIdx - d->begIdx );
return kInvalidArgRC;
}
cw::rc_t cw::audio::device::deviceStop( handle_t h, unsigned devIdx )
{
drv_t* d;
if((d = _indexToDriver(h,devIdx)) != nullptr )
return d->drv->deviceStop( d->drv, devIdx - d->begIdx );
return kInvalidArgRC;
}
bool cw::audio::device::deviceIsStarted(handle_t h, unsigned devIdx )
{
drv_t* d;
if((d = _indexToDriver(h,devIdx)) != nullptr )
return d->drv->deviceIsStarted( d->drv, devIdx - d->begIdx );
return false;
}
void cw::audio::device::deviceRealTimeReport( handle_t h, unsigned devIdx )
{
drv_t* d;
if((d = _indexToDriver(h,devIdx)) != nullptr )
d->drv->deviceRealTimeReport( d->drv, devIdx - d->begIdx );
}
void cw::audio::device::report( handle_t h )
{
for(unsigned i=0; i<deviceCount(h); ++i)
{
cwLogInfo( "%8.1f in:%i (%i) out:%i (%i) %s",
deviceSampleRate(h,i),
deviceChannelCount(h,i,true), deviceFramesPerCycle(h,i,true),
deviceChannelCount(h,i,false), deviceFramesPerCycle(h,i,false),
deviceLabel(h,i));
}
}

95
cwAudioDevice.h Normal file
View File

@ -0,0 +1,95 @@
#ifndef cwAudioDevice_H
#define cwAudioDevice_H
namespace cw
{
namespace audio
{
namespace device
{
typedef float sample_t;
// audioPacket_t flags
enum
{
kInterleavedApFl = 0x01, // The audio samples are interleaved.
kFloatApFl = 0x02 // The audio samples are single precision floating point values.
};
// Audio packet record used by the audioPacket_t callback.
// Audio ports send and receive audio using this data structure.
typedef struct
{
unsigned devIdx; // device associated with packet
unsigned begChIdx; // first device channel
unsigned chCnt; // count of channels
unsigned audioFramesCnt; // samples per channel (see note below)
unsigned bitsPerSample; // bits per sample word
unsigned flags; // kInterleavedApFl | kFloatApFl
void* audioBytesPtr; // pointer to sample data
void* cbArg; // user defined argument passed in via deviceSetup()
time::spec_t timeStamp; // Packet time stamp.
} audioPacket_t;
// Audio port callback signature.
// inPktArray[inPktCnt] are full packets of audio coming from the ADC to the application.
// outPktArray[outPktCnt] are empty packets of audio which will be filled by the application
// and then sent to the DAC.
//
// The value of audioFrameCnt gives the number of samples per channel which are available
// in the packet data buffer 'audioBytesPtr'. The callback function may decrease this number in
// output packets if the number of samples available is less than the size of the buffer.
// It is the responsibility of the calling audio port to notice this change and pass the new,
// decreased number of samples to the hardware.
//
// In general it should be assmed that this call is made from a system thread which is not
// the same as the application thread.
// The usual thread safety precautions should therefore be taken if this function implementation
// interacts with data structures also handled by the application. The audio buffer class (\see cmApBuf.h)
// is designed to provide a safe and efficient way to communicate between
// the audio thread and the application.
typedef void (*cbFunc_t)( audioPacket_t* inPktArray, unsigned inPktCnt, audioPacket_t* outPktArray, unsigned outPktCnt );
typedef struct driver_str
{
void* drvArg;
rc_t (*deviceCount)( struct driver_str* drvArg);
const char* (*deviceLabel)( struct driver_str* drvArg, unsigned devIdx );
unsigned (*deviceChannelCount)( struct driver_str* drvArg, unsigned devIdx, bool inputFl );
double (*deviceSampleRate)( struct driver_str* drvArg, unsigned devIdx );
unsigned (*deviceFramesPerCycle)( struct driver_str* drvArg, unsigned devIdx, bool inputFl );
rc_t (*deviceSetup)( struct driver_str* drvArg, unsigned devIdx, double sr, unsigned frmPerCycle, cbFunc_t cb, void* cbData );
rc_t (*deviceStart)( struct driver_str* drvArg, unsigned devIdx );
rc_t (*deviceStop)( struct driver_str* drvArg, unsigned devIdx );
bool (*deviceIsStarted)( struct driver_str* drvArg, unsigned devIdx );
void (*deviceRealTimeReport)( struct driver_str* drvArg, unsigned devIdx );
} driver_t;
typedef handle<struct device_str> handle_t;
rc_t create( handle_t& hRef );
rc_t destroy( handle_t& hRef );
rc_t registerDriver( handle_t h, driver_t* drv );
unsigned deviceCount( handle_t h );
unsigned deviceLabelToIndex( handle_t h, const char* label );
const char* deviceLabel( handle_t h, unsigned devIdx );
unsigned deviceChannelCount( handle_t h, unsigned devIdx, bool inputFl );
double deviceSampleRate( handle_t h, unsigned devIdx );
unsigned deviceFramesPerCycle( handle_t h, unsigned devIdx, bool inputFl );
rc_t deviceSetup( handle_t h, unsigned devIdx, double sr, unsigned frmPerCycle, cbFunc_t cb, void* cbData );
rc_t deviceStart( handle_t h, unsigned devIdx );
rc_t deviceStop( handle_t h, unsigned devIdx );
bool deviceIsStarted( handle_t h, unsigned devIdx );
void deviceRealTimeReport( handle_t h, unsigned devIdx );
void report( handle_t h );
}
}
}
#endif

File diff suppressed because it is too large Load Diff

37
cwAudioDeviceAlsa.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef cwAudioDeviceAlsa_H
#define cwAudioDeviceAlsa_H
namespace cw
{
namespace audio
{
namespace device
{
namespace alsa
{
typedef handle<struct alsa_str> handle_t;
rc_t create( handle_t& hRef, struct driver_str*& drvRef );
rc_t destroy( handle_t& hRef );
unsigned deviceCount( struct driver_str* drv);
const char* deviceLabel( struct driver_str* drv, unsigned devIdx );
unsigned deviceChannelCount( struct driver_str* drv, unsigned devIdx, bool inputFl );
double deviceSampleRate( struct driver_str* drv, unsigned devIdx );
unsigned deviceFramesPerCycle( struct driver_str* drv, unsigned devIdx, bool inputFl );
rc_t deviceSetup( struct driver_str* drv, unsigned devIdx, double sr, unsigned frmPerCycle, cbFunc_t cbFunc, void* cbArg );
rc_t deviceStart( struct driver_str* drv, unsigned devIdx );
rc_t deviceStop( struct driver_str* drv, unsigned devIdx );
bool deviceIsStarted( struct driver_str* drv, unsigned devIdx );
void deviceRealTimeReport( struct driver_str* drv, unsigned devIdx );
void report(handle_t h );
void report();
}
}
}
}
#endif

View File

@ -2,375 +2,12 @@
#include "cwLog.h"
#include "cwCommonImpl.h"
#include "cwMem.h"
#include "cwTextBuf.h"
#include "cwTime.h"
#include "cwAudioPort.h"
#include "cwTextBuf.h"
#include "cwAudioDevice.h"
#include "cwAudioBuf.h"
#ifdef cwLINUX
#include "cwAudioPortAlsa.h"
#endif
#ifdef cwOSX
#include "cmAudioPortOsx.h"
#endif
namespace cw
{
namespace audio
{
namespace device
{
typedef struct
{
unsigned begDevIdx;
unsigned endDevIdx;
rc_t (*initialize)( unsigned baseApDevIdx );
rc_t (*finalize)();
rc_t (*deviceCount)();
const char* (*deviceLabel)( unsigned devIdx );
unsigned (*deviceChannelCount)( unsigned devIdx, bool inputFl );
double (*deviceSampleRate)( unsigned devIdx );
unsigned (*deviceFramesPerCycle)( unsigned devIdx, bool inputFl );
rc_t (*deviceSetup)( unsigned devIdx, double sr, unsigned frmPerCycle, cbFunc_t cb, void* cbData );
rc_t (*deviceStart)( unsigned devIdx );
rc_t (*deviceStop)( unsigned devIdx );
bool (*deviceIsStarted)( unsigned devIdx );
} cmApDriver_t;
typedef struct
{
cmApDriver_t* drvArray;
unsigned drvCnt;
unsigned devCnt;
} cmAp_t;
cmAp_t* _ap = NULL;
rc_t _cmApIndexToDev( unsigned devIdx, cmApDriver_t** drvPtrPtr, unsigned* devIdxPtr )
{
assert( drvPtrPtr != NULL && devIdxPtr != NULL );
*drvPtrPtr = NULL;
*devIdxPtr = kInvalidIdx;
unsigned i;
for(i=0; i<_ap->drvCnt; ++i)
if( _ap->drvArray[i].begDevIdx != kInvalidIdx )
if( (_ap->drvArray[i].begDevIdx <= devIdx) && (devIdx <= _ap->drvArray[i].endDevIdx) )
{
*drvPtrPtr = _ap->drvArray + i;
*devIdxPtr = devIdx - _ap->drvArray[i].begDevIdx;
return kOkRC;
}
return cwLogError(kInvalidIdRC,"The audio port device index %i is not valid.",devIdx);
}
}
}
}
cw::rc_t cw::audio::device::initialize()
{
rc_t rc = kOkRC;
if((rc = finalize()) != kOkRC )
return rc;
_ap = memAllocZ<cmAp_t>(1);
_ap->drvCnt = 1;
_ap->drvArray = memAllocZ<cmApDriver_t>(_ap->drvCnt);
cmApDriver_t* dp = _ap->drvArray;
#ifdef cwOSX
dp->initialize = cmApOsxInitialize;
dp->finalize = cmApOsxFinalize;
dp->deviceCount = cmApOsxDeviceCount;
dp->deviceLabel = cmApOsxDeviceLabel;
dp->deviceChannelCount = cmApOsxDeviceChannelCount;
dp->deviceSampleRate = cmApOsxDeviceSampleRate;
dp->deviceFramesPerCycle = cmApOsxDeviceFramesPerCycle;
dp->deviceSetup = cmApOsxDeviceSetup;
dp->deviceStart = cmApOsxDeviceStart;
dp->deviceStop = cmApOsxDeviceStop;
dp->deviceIsStarted = cmApOsxDeviceIsStarted;
#endif
#ifdef cwLINUX
dp->initialize = alsa::initialize;
dp->finalize = alsa::finalize;
dp->deviceCount = alsa::deviceCount;
dp->deviceLabel = alsa::deviceLabel;
dp->deviceChannelCount = alsa::deviceChannelCount;
dp->deviceSampleRate = alsa::deviceSampleRate;
dp->deviceFramesPerCycle = alsa::deviceFramesPerCycle;
dp->deviceSetup = alsa::deviceSetup;
dp->deviceStart = alsa::deviceStart;
dp->deviceStop = alsa::deviceStop;
dp->deviceIsStarted = alsa::deviceIsStarted;
#endif
/*
dp = _ap->drvArray + 1;
dp->initialize = cmApFileInitialize;
dp->finalize = cmApFileFinalize;
dp->deviceCount = cmApFileDeviceCount;
dp->deviceLabel = cmApFileDeviceLabel;
dp->deviceChannelCount = cmApFileDeviceChannelCount;
dp->deviceSampleRate = cmApFileDeviceSampleRate;
dp->deviceFramesPerCycle = cmApFileDeviceFramesPerCycle;
dp->deviceSetup = cmApFileDeviceSetup;
dp->deviceStart = cmApFileDeviceStart;
dp->deviceStop = cmApFileDeviceStop;
dp->deviceIsStarted = cmApFileDeviceIsStarted;
dp = _ap->drvArray + 2;
dp->initialize = cmApAggInitialize;
dp->finalize = cmApAggFinalize;
dp->deviceCount = cmApAggDeviceCount;
dp->deviceLabel = cmApAggDeviceLabel;
dp->deviceChannelCount = cmApAggDeviceChannelCount;
dp->deviceSampleRate = cmApAggDeviceSampleRate;
dp->deviceFramesPerCycle = cmApAggDeviceFramesPerCycle;
dp->deviceSetup = cmApAggDeviceSetup;
dp->deviceStart = cmApAggDeviceStart;
dp->deviceStop = cmApAggDeviceStop;
dp->deviceIsStarted = cmApAggDeviceIsStarted;
dp = _ap->drvArray + 3;
dp->initialize = cmApNrtInitialize;
dp->finalize = cmApNrtFinalize;
dp->deviceCount = cmApNrtDeviceCount;
dp->deviceLabel = cmApNrtDeviceLabel;
dp->deviceChannelCount = cmApNrtDeviceChannelCount;
dp->deviceSampleRate = cmApNrtDeviceSampleRate;
dp->deviceFramesPerCycle = cmApNrtDeviceFramesPerCycle;
dp->deviceSetup = cmApNrtDeviceSetup;
dp->deviceStart = cmApNrtDeviceStart;
dp->deviceStop = cmApNrtDeviceStop;
dp->deviceIsStarted = cmApNrtDeviceIsStarted;
*/
_ap->devCnt = 0;
unsigned i;
for(i=0; i<_ap->drvCnt; ++i)
{
unsigned dn;
rc_t rc0;
_ap->drvArray[i].begDevIdx = kInvalidIdx;
_ap->drvArray[i].endDevIdx = kInvalidIdx;
if((rc0 = _ap->drvArray[i].initialize(_ap->devCnt)) != kOkRC )
{
rc = rc0;
continue;
}
if((dn = _ap->drvArray[i].deviceCount()) > 0)
{
_ap->drvArray[i].begDevIdx = _ap->devCnt;
_ap->drvArray[i].endDevIdx = _ap->devCnt + dn - 1;
_ap->devCnt += dn;
}
}
if( rc != kOkRC )
finalize();
return rc;
}
cw::rc_t cw::audio::device::finalize()
{
rc_t rc=kOkRC;
rc_t rc0 = kOkRC;
unsigned i;
if( _ap == NULL )
return kOkRC;
for(i=0; i<_ap->drvCnt; ++i)
{
if((rc0 = _ap->drvArray[i].finalize()) != kOkRC )
rc = rc0;
}
memRelease(_ap->drvArray);
memRelease(_ap);
return rc;
}
unsigned cw::audio::device::deviceCount()
{ return _ap->devCnt; }
const char* cw::audio::device::deviceLabel( unsigned devIdx )
{
cmApDriver_t* dp = NULL;
unsigned di = kInvalidIdx;
rc_t rc;
if( devIdx == kInvalidIdx )
return NULL;
if((rc = _cmApIndexToDev(devIdx,&dp,&di)) != kOkRC )
return cwStringNullGuard(NULL);
return dp->deviceLabel(di);
}
unsigned cw::audio::device::deviceLabelToIndex( const char* label )
{
unsigned n = deviceCount();
unsigned i;
for(i=0; i<n; ++i)
{
const char* s = deviceLabel(i);
if( s!=NULL && strcmp(s,label)==0)
return i;
}
return kInvalidIdx;
}
unsigned cw::audio::device::deviceChannelCount( unsigned devIdx, bool inputFl )
{
cmApDriver_t* dp = NULL;
unsigned di = kInvalidIdx;
rc_t rc;
if( devIdx == kInvalidIdx )
return 0;
if((rc = _cmApIndexToDev(devIdx,&dp,&di)) != kOkRC )
return rc;
return dp->deviceChannelCount(di,inputFl);
}
double cw::audio::device::deviceSampleRate( unsigned devIdx )
{
cmApDriver_t* dp = NULL;
unsigned di = kInvalidIdx;
rc_t rc;
if((rc = _cmApIndexToDev(devIdx,&dp,&di)) != kOkRC )
return rc;
return dp->deviceSampleRate(di);
}
unsigned cw::audio::device::deviceFramesPerCycle( unsigned devIdx, bool inputFl )
{
cmApDriver_t* dp = NULL;
unsigned di = kInvalidIdx;
rc_t rc;
if( devIdx == kInvalidIdx )
return 0;
if((rc = _cmApIndexToDev(devIdx,&dp,&di)) != kOkRC )
return rc;
return dp->deviceFramesPerCycle(di,inputFl);
}
cw::rc_t cw::audio::device::deviceSetup(
unsigned devIdx,
double srate,
unsigned framesPerCycle,
cbFunc_t cbFunc,
void* cbArg )
{
cmApDriver_t* dp;
unsigned di;
rc_t rc;
if( devIdx == kInvalidIdx )
return kOkRC;
if((rc = _cmApIndexToDev(devIdx,&dp,&di)) != kOkRC )
return rc;
return dp->deviceSetup(di,srate,framesPerCycle,cbFunc,cbArg);
}
cw::rc_t cw::audio::device::deviceStart( unsigned devIdx )
{
cmApDriver_t* dp;
unsigned di;
rc_t rc;
if( devIdx == kInvalidIdx )
return kOkRC;
if((rc = _cmApIndexToDev(devIdx,&dp,&di)) != kOkRC )
return rc;
return dp->deviceStart(di);
}
cw::rc_t cw::audio::device::deviceStop( unsigned devIdx )
{
cmApDriver_t* dp;
unsigned di;
rc_t rc;
if( devIdx == kInvalidIdx )
return kOkRC;
if((rc = _cmApIndexToDev(devIdx,&dp,&di)) != kOkRC )
return rc;
return dp->deviceStop(di);
}
bool cw::audio::device::deviceIsStarted( unsigned devIdx )
{
cmApDriver_t* dp;
unsigned di;
rc_t rc;
if( devIdx == kInvalidIdx )
return false;
if((rc = _cmApIndexToDev(devIdx,&dp,&di)) != kOkRC )
return rc;
return dp->deviceIsStarted(di);
}
void cw::audio::device::report()
{
unsigned i,j,k;
for(j=0,k=0; j<_ap->drvCnt; ++j)
{
cmApDriver_t* drvPtr = _ap->drvArray + j;
unsigned n = drvPtr->deviceCount();
for(i=0; i<n; ++i,++k)
{
cwLogInfo( "%i %f in:%i (%i) out:%i (%i) %s",
k, drvPtr->deviceSampleRate(i),
drvPtr->deviceChannelCount(i,true), drvPtr->deviceFramesPerCycle(i,true),
drvPtr->deviceChannelCount(i,false), drvPtr->deviceFramesPerCycle(i,false),
drvPtr->deviceLabel(i));
}
}
//cmApAlsaDeviceReport(rpt);
}
#include "cwAudioDeviceAlsa.h"
#include "cwAudioDeviceTest.h"
namespace cw
{
@ -380,7 +17,7 @@ namespace cw
{
/// [cmAudioPortExample]
// See cmApPortTest() below for the main point of entry.
// See test() below for the main point of entry.
// Data structure used to hold the parameters for cpApPortTest()
// and the user defined data record passed to the host from the
@ -640,8 +277,10 @@ namespace cw
cwLogInfo(msg);
}
// Get a command line option.
int _cmApGetOpt( int argc, const char* argv[], const char* label, int defaultVal, bool boolFl )
// Get a command line option. Note that if 'boolFl' is set to 'true' then the function simply
// returns '1'. This is used to handle arguments whose presense indicates a positive boolean
// flag. For example -h (help) indicates that the usage data should be printed - it needs no other argument.
int _cmApGetOpt( int argc, const char* argv[], const char* label, int defaultVal, bool boolFl=false )
{
int i = 0;
for(; i<argc; ++i)
@ -664,6 +303,12 @@ namespace cw
void _cmApPortCb2( audioPacket_t* inPktArray, unsigned inPktCnt, audioPacket_t* outPktArray, unsigned outPktCnt )
{
for(unsigned i=0; i<inPktCnt; ++i)
static_cast<cmApPortTestRecd*>(inPktArray[i].cbArg)->cbCnt++;
for(unsigned i=0; i<outPktCnt; ++i)
static_cast<cmApPortTestRecd*>(outPktArray[i].cbArg)->cbCnt++;
buf::inputToOutput( _cmGlobalInDevIdx, _cmGlobalOutDevIdx );
buf::update( inPktArray, inPktCnt, outPktArray, outPktCnt );
@ -673,23 +318,26 @@ namespace cw
}
// Audio Port testing function
cw::rc_t cw::audio::device::test( bool runFl, int argc, const char** argv )
cw::rc_t cw::audio::device::test( int argc, const char** argv )
{
cmApPortTestRecd r;
unsigned i;
int result = 0;
textBuf::handle_t tbH = textBuf::create();
rc_t rc;
driver_t* drv = nullptr;
handle_t h;
alsa::handle_t alsaH;
bool runFl = true;
if( _cmApGetOpt(argc,argv,"-h",0,true) )
_cmApPrintUsage();
runFl = _cmApGetOpt(argc,argv,"-p",!runFl,true)?false:true;
r.srate = _cmApGetOpt(argc,argv,"-r",44100,false);
r.chIdx = _cmApGetOpt(argc,argv,"-a",0,false);
r.chCnt = _cmApGetOpt(argc,argv,"-c",2,false);
r.bufCnt = _cmApGetOpt(argc,argv,"-b",3,false);
r.framesPerCycle = _cmApGetOpt(argc,argv,"-f",512,false);
runFl = _cmApGetOpt(argc,argv,"-p",0,true)?false:true;
r.srate = _cmApGetOpt(argc,argv,"-r",44100);
r.chIdx = _cmApGetOpt(argc,argv,"-a",0);
r.chCnt = _cmApGetOpt(argc,argv,"-c",2);
r.bufCnt = _cmApGetOpt(argc,argv,"-b",3);
r.framesPerCycle = _cmApGetOpt(argc,argv,"-f",512);
r.bufFrmCnt = (r.bufCnt*r.framesPerCycle);
r.bufSmpCnt = (r.chCnt * r.bufFrmCnt);
r.logCnt = 100;
@ -699,8 +347,8 @@ cw::rc_t cw::audio::device::test( bool runFl, int argc, const char** argv )
char log[r.logCnt];
unsigned ilog[r.logCnt];
r.inDevIdx = _cmGlobalInDevIdx = _cmApGetOpt(argc,argv,"-i",0,false);
r.outDevIdx = _cmGlobalOutDevIdx = _cmApGetOpt(argc,argv,"-o",2,false);
r.inDevIdx = _cmGlobalInDevIdx = _cmApGetOpt(argc,argv,"-i",0);
r.outDevIdx = _cmGlobalOutDevIdx = _cmApGetOpt(argc,argv,"-o",2);
r.phase = 0;
r.frqHz = 2000;
r.bufInIdx = 0;
@ -713,75 +361,75 @@ cw::rc_t cw::audio::device::test( bool runFl, int argc, const char** argv )
r.ilog = ilog;
r.cbCnt = 0;
cwLogInfo("%s in:%i out:%i chidx:%i chs:%i bufs=%i frm=%i rate=%f",runFl?"exec":"rpt",r.inDevIdx,r.outDevIdx,r.chIdx,r.chCnt,r.bufCnt,r.framesPerCycle,r.srate);
cwLogInfo("Program cfg: %s in:%i out:%i chidx:%i chs:%i bufs=%i frm=%i rate=%f",runFl?"exec":"rpt",r.inDevIdx,r.outDevIdx,r.chIdx,r.chCnt,r.bufCnt,r.framesPerCycle,r.srate);
/*
if( cmApFileAllocate(rpt) != kOkRC )
{
cwLogInfo("Audio port file allocation failed.");
result = -1;
goto errLabel;
}
// allocate the non-real-time port
if( cmApNrtAllocate(rpt) != kOkRC )
{
cwLogInfo("Non-real-time system allocation failed.");
result = 1;
goto errLabel;
}
*/
// initialize the audio device interface
if( initialize() != kOkRC )
if((rc = create(h)) != kOkRC )
{
cwLogInfo("Initialize failed.");
result = 1;
goto errLabel;
}
// initialize the ALSA device driver interface
if((rc = alsa::create(alsaH, drv )) != kOkRC )
{
cwLogInfo("ALSA initialize failed.");
goto errLabel;
}
// register the ALSA device driver with the audio interface
if((rc = registerDriver( h, drv )) != kOkRC )
{
cwLogInfo("ALSA driver registration failed.");
goto errLabel;
}
// report the current audio device configuration
for(i=0; i<deviceCount(); ++i)
for(i=0; i<deviceCount(h); ++i)
{
cwLogInfo("%i [in: chs=%i frames=%i] [out: chs=%i frames=%i] srate:%f %s",i,deviceChannelCount(i,true),deviceFramesPerCycle(i,true),deviceChannelCount(i,false),deviceFramesPerCycle(i,false),deviceSampleRate(i),deviceLabel(i));
cwLogInfo("%i [in: chs=%i frames=%i] [out: chs=%i frames=%i] srate:%f %s",i,deviceChannelCount(h,i,true),deviceFramesPerCycle(h,i,true),deviceChannelCount(h,i,false),deviceFramesPerCycle(h,i,false),deviceSampleRate(h,i),deviceLabel(h,i));
}
// report the current audio devices using the audio port interface function
report();
report(h);
if( runFl )
{
// initialize the audio bufer
buf::initialize( deviceCount(), r.meterMs );
buf::initialize( deviceCount(h), r.meterMs );
// setup the buffer for the output device
buf::setup( r.outDevIdx, r.srate, r.framesPerCycle, r.bufCnt, deviceChannelCount(r.outDevIdx,true), r.framesPerCycle, deviceChannelCount(r.outDevIdx,false), r.framesPerCycle );
buf::setup( r.outDevIdx, r.srate, r.framesPerCycle, r.bufCnt, deviceChannelCount(h,r.outDevIdx,true), r.framesPerCycle, deviceChannelCount(h,r.outDevIdx,false), r.framesPerCycle );
// setup the buffer for the input device
if( r.inDevIdx != r.outDevIdx )
buf::setup( r.inDevIdx, r.srate, r.framesPerCycle, r.bufCnt, deviceChannelCount(r.inDevIdx,true), r.framesPerCycle, deviceChannelCount(r.inDevIdx,false), r.framesPerCycle );
buf::setup( r.inDevIdx, r.srate, r.framesPerCycle, r.bufCnt, deviceChannelCount(h,r.inDevIdx,true), r.framesPerCycle, deviceChannelCount(h,r.inDevIdx,false), r.framesPerCycle );
// setup an output device
if(deviceSetup(r.outDevIdx,r.srate,r.framesPerCycle,_cmApPortCb2,&r) != kOkRC )
if(deviceSetup(h, r.outDevIdx,r.srate,r.framesPerCycle,_cmApPortCb2,&r) != kOkRC )
cwLogInfo("Out device setup failed.");
else
// setup an input device
if( deviceSetup(r.inDevIdx,r.srate,r.framesPerCycle,_cmApPortCb2,&r) != kOkRC )
if( deviceSetup(h, r.inDevIdx,r.srate,r.framesPerCycle,_cmApPortCb2,&r) != kOkRC )
cwLogInfo("In device setup failed.");
else
// start the input device
if( deviceStart(r.inDevIdx) != kOkRC )
if( deviceStart(h, r.inDevIdx) != kOkRC )
cwLogInfo("In device start failed.");
else
// start the output device
if( deviceStart(r.outDevIdx) != kOkRC )
if( deviceStart(h, r.outDevIdx) != kOkRC )
cwLogInfo("Out Device start failed.");
else
cwLogInfo("Setup complete!");
cwLogInfo("q=quit O/o output tone, I/i input tone P/p pass");
cwLogInfo("q=quit O/o output tone, I/i input tone P/p pass s=buf report");
char c;
while((c=getchar()) != 'q')
{
//cmApAlsaDeviceRtReport(rpt,r.outDevIdx);
deviceRealTimeReport(h, r.outDevIdx );
switch(c)
{
@ -801,48 +449,42 @@ cw::rc_t cw::audio::device::test( bool runFl, int argc, const char** argv )
break;
case 's':
buf::report(tbH);
cwLogInfo("%s",textBuf::text(tbH));
textBuf::clear(tbH);
buf::report();
break;
}
}
// stop the input device
if( deviceIsStarted(r.inDevIdx) )
if( deviceStop(r.inDevIdx) != kOkRC )
if( deviceIsStarted(h,r.inDevIdx) )
if( deviceStop(h,r.inDevIdx) != kOkRC )
cwLogInfo("In device stop failed.");
// stop the output device
if( deviceIsStarted(r.outDevIdx) )
if( deviceStop(r.outDevIdx) != kOkRC )
if( deviceIsStarted(h,r.outDevIdx) )
if( deviceStop(h,r.outDevIdx) != kOkRC )
cwLogInfo("Out device stop failed.");
}
errLabel:
// release any resources held by the audio port interface
if( finalize() != kOkRC )
cwLogInfo("Finalize failed.");
// release the ALSA driver
rc_t rc0 = alsa::destroy(alsaH);
buf::finalize();
// release any resources held by the audio port interface
rc_t rc1 = destroy(h);
rc_t rc2 = buf::finalize();
//cmApNrtFree();
//cmApFileFree();
// report the count of audio buffer callbacks
cwLogInfo("cb count:%i", r.cbCnt );
//for(i=0; i<_logCnt; ++i)
// cwLogInfo("%c(%i)",_log[i],_ilog[i]);
//cwLogInfo("\n");
textBuf::destroy(tbH);
return result;
return rcSelect(rc,rc0,rc1,rc2);
}
/// [cmAudioPortExample]

15
cwAudioDeviceTest.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef cwAudioDeviceTest_H
#define cwAudioDeviceTest_H
namespace cw
{
namespace audio
{
namespace device
{
rc_t test( int argc, const char** argv );
}
}
}
#endif

View File

@ -1,119 +0,0 @@
//( { file_desc: "Cross platform audio device interface." kw:[audio rt] }
//
// This interface provides data declarations for platform dependent
// audio I/O functions. The implementation for the functions are
// in platform specific modules. See cmAudioPortOsx.c and cmAudioPortAlsa.c.
//
// ALSA Notes:
// Assign capture device to line or mic input:
// amixer -c 0 cset iface=MIXER,name='Input Source',index=0 Mic
// amixer -c 0 cset iface=MIXER,name='Input Source',index=0 Line
//
// -c 0 select the first card
// -iface=MIXER the cset is targetting the MIXER component
// -name='Input Source',index=0 the control to set is the first 'Input Source'
// Note that the 'Capture' control sets the input gain.
//
// See alsamixer for a GUI to accomplish the same thing.
//
//
//)
#ifndef cwAudioPort_H
#define cwAudioPort_H
namespace cw
{
namespace audio
{
namespace device
{
typedef float sample_t;
// audioPacket_t flags
enum
{
kInterleavedApFl = 0x01, // The audio samples are interleaved.
kFloatApFl = 0x02 // The audio samples are single precision floating point values.
};
// Audio packet record used by the audioPacket_t callback.
// Audio ports send and receive audio using this data structure.
typedef struct
{
unsigned devIdx; // device associated with packet
unsigned begChIdx; // first device channel
unsigned chCnt; // count of channels
unsigned audioFramesCnt; // samples per channel (see note below)
unsigned bitsPerSample; // bits per sample word
unsigned flags; // kInterleavedApFl | kFloatApFl
void* audioBytesPtr; // pointer to sample data
void* userCbPtr; // user defined argument passed in via deviceSetup()
time::spec_t timeStamp; // Packet time stamp.
} audioPacket_t;
// Audio port callback signature.
// inPktArray[inPktCnt] are full packets of audio coming from the ADC to the application.
// outPktArray[outPktCnt] are empty packets of audio which will be filled by the application
// and then sent to the DAC.
//
// The value of audioFrameCnt gives the number of samples per channel which are available
// in the packet data buffer 'audioBytesPtr'. The callback function may decrease this number in
// output packets if the number of samples available is less than the size of the buffer.
// It is the responsibility of the calling audio port to notice this change and pass the new,
// decreased number of samples to the hardware.
//
// In general it should be assmed that this call is made from a system thread which is not
// the same as the application thread.
// The usual thread safety precautions should therefore be taken if this function implementation
// interacts with data structures also handled by the application. The audio buffer class (\see cmApBuf.h)
// is designed to provide a safe and efficient way to communicate between
// the audio thread and the application.
typedef void (*cbFunc_t)( audioPacket_t* inPktArray, unsigned inPktCnt, audioPacket_t* outPktArray, unsigned outPktCnt );
rc_t initialize();
rc_t finalize();
unsigned deviceCount();
const char* deviceLabel( unsigned devIdx );
unsigned deviceLabelToIndex( const char* label );
unsigned deviceChannelCount( unsigned devIdx, bool inputFl );
// Get the current sample rate of a device. Note that if the device has both
// input and output capability then the sample rate is the same for both.
double deviceSampleRate( unsigned devIdx );
unsigned deviceFramesPerCycle( unsigned devIdx, bool inputFl );
// Configure a device.
// All devices must be setup before they are started.
// framesPerCycle is the requested number of samples per audio callback. The
// actual number of samples made from a callback may be smaller. See the note
// regarding this in audioPacket_t.
// If the device cannot support the requested configuration then the function
// will return an error code.
// If the device is started when this function is called then it will be
// automatically stopped and then restarted following the reconfiguration.
// If the reconfiguration fails then the device may not be restared.
rc_t deviceSetup( unsigned devIdx, double srate, unsigned framesPerCallback, cbFunc_t cbFunc, void* cbArg );
// Start a device. Note that the callback may be made prior to this function returning.
rc_t deviceStart( unsigned devIdx );
rc_t deviceStop( unsigned devIdx );
bool deviceIsStarted( unsigned devIdx );
// Print a report of all the current audio device configurations.
void report();
// Test the audio port by synthesizing a sine signal or passing audio through
// from the input to the output. This is also a good example of how to
// use all of the functions in the interface.
// Set runFl to false to print a report without starting any audio devices.
// See cmAudiotPortTest.c for usage example for this function.
rc_t test( bool runFl, int argc, const char** argv );
}
}
}
#endif

View File

@ -1,53 +0,0 @@
#ifndef cwAudioPortAlsa_H
#define cwAudioPortAlsa_H
namespace cw
{
namespace audio
{
namespace device
{
namespace alsa
{
//{ { label: cmApAlsa kw:[ audio, device, rt ] }
//
//(
// ALSA audio device API
//
// This API is used by the cmAudioPort interface when
// the library is compiled for a Linux platform.
//
//)
//[
rc_t initialize( unsigned baseApDevIdx );
rc_t finalize();
rc_t deviceCount();
const char* deviceLabel( unsigned devIdx );
unsigned deviceChannelCount( unsigned devIdx, bool inputFl );
double deviceSampleRate( unsigned devIdx );
unsigned deviceFramesPerCycle( unsigned devIdx, bool inputFl );
rc_t deviceSetup(
unsigned devIdx,
double srate,
unsigned framesPerCycle,
device::cbFunc_t callbackPtr,
void* userCbPtr );
rc_t deviceStart( unsigned devIdx );
rc_t deviceStop( unsigned devIdx );
bool deviceIsStarted( unsigned devIdx );
void deviceReport( );
//]
//}
}
}
}
}
#endif

View File

@ -64,6 +64,19 @@ namespace cw
const char* idToLabel( const idLabelPair_t* array, unsigned id, unsigned eolId );
unsigned labelToId( const idLabelPair_t* array, const char* label, unsigned eolId );
inline rc_t rcSelect() { return kOkRC; }
template<typename T, typename... ARGS>
rc_t rcSelect(T rc, ARGS... args)
{
if( rc != kOkRC )
return rc;
return rcSelect(args...);
}
void sleepSec( unsigned secs ); // sleep seconds
void sleepMs( unsigned ms ); // sleep milliseconds
void sleepUs( unsigned us ); // sleep seconds

View File

@ -14,132 +14,138 @@
namespace cw
{
typedef struct file_str
namespace file
{
FILE* fp;
char* fnStr;
} file_t;
typedef struct file_str
{
FILE* fp;
char* fnStr;
} this_t;
#define _fileHandleToPtr(h) handleToPtr<fileH_t,file_t>(h)
this_t* _handleToPtr(handle_t h)
{
return handleToPtr<handle_t,this_t>(h);
}
char* _fileToBuf( fileH_t h, unsigned nn, unsigned* bufByteCntPtr )
{
errno = 0;
char* _fileToBuf( handle_t h, unsigned nn, unsigned* bufByteCntPtr )
{
errno = 0;
unsigned n = fileByteCount(h);
char* buf = nullptr;
unsigned n = byteCount(h);
char* buf = nullptr;
// if the file size calculation is ok
if( errno != 0 )
{
cwLogSysError(kOpFailRC,errno,"Invalid file buffer length on '%s'.", cwStringNullGuard(name(h)));
goto errLabel;
}
// allocate the read target buffer
if((buf = memAlloc<char>(n+nn)) == nullptr)
{
cwLogError(kMemAllocFailRC,"Read buffer allocation failed.");
goto errLabel;
}
// read the file
if( read(h,buf,n) != kOkRC )
goto errLabel;
// zero memory after the file data
memset(buf+n,0,nn);
if( bufByteCntPtr != nullptr )
*bufByteCntPtr = n;
return buf;
errLabel:
if( bufByteCntPtr != nullptr )
*bufByteCntPtr = 0;
memRelease(buf);
return nullptr;
}
char* _fileFnToBuf( const char* fn, unsigned nn, unsigned* bufByteCntPtr )
{
handle_t h;
char* buf = nullptr;
if( open(h,fn,kReadFl | kBinaryFl) != kOkRC )
goto errLabel;
buf = _fileToBuf(h,nn,bufByteCntPtr);
errLabel:
close(h);
return buf;
}
rc_t _fileGetLine( this_t* p, char* buf, unsigned* bufByteCntPtr )
{
// fgets() reads up to n-1 bytes into buf[]
if( fgets(buf,*bufByteCntPtr,p->fp) == nullptr )
{
// an read error or EOF condition occurred
*bufByteCntPtr = 0;
if( !feof(p->fp ) )
return cwLogSysError(kReadFailRC,errno,"File read line failed");
return kReadFailRC;
}
return kOkRC;
}
// if the file size calculation is ok
if( errno != 0 )
{
cwLogSysError(kOpFailRC,errno,"Invalid file buffer length on '%s'.", cwStringNullGuard(fileName(h)));
goto errLabel;
}
// allocate the read target buffer
if((buf = memAlloc<char>(n+nn)) == nullptr)
{
cwLogError(kMemAllocFailRC,"Read buffer allocation failed.");
goto errLabel;
}
// read the file
if( fileRead(h,buf,n) != kOkRC )
goto errLabel;
// zero memory after the file data
memset(buf+n,0,nn);
if( bufByteCntPtr != nullptr )
*bufByteCntPtr = n;
return buf;
errLabel:
if( bufByteCntPtr != nullptr )
*bufByteCntPtr = 0;
memRelease(buf);
return nullptr;
}
char* _fileFnToBuf( const char* fn, unsigned nn, unsigned* bufByteCntPtr )
{
fileH_t h;
char* buf = nullptr;
if( fileOpen(h,fn,kReadFileFl | kBinaryFileFl) != kOkRC )
goto errLabel;
buf = _fileToBuf(h,nn,bufByteCntPtr);
errLabel:
fileClose(h);
return buf;
}
rc_t _fileGetLine( file_t* p, char* buf, unsigned* bufByteCntPtr )
{
// fgets() reads up to n-1 bytes into buf[]
if( fgets(buf,*bufByteCntPtr,p->fp) == nullptr )
{
// an read error or EOF condition occurred
*bufByteCntPtr = 0;
if( !feof(p->fp ) )
return cwLogSysError(kReadFailRC,errno,"File read line failed");
return kReadFailRC;
}
return kOkRC;
}
}
cw::rc_t cw::fileOpen( fileH_t& hRef, const char* fn, unsigned flags )
cw::rc_t cw::file::open( handle_t& hRef, const char* fn, unsigned flags )
{
char mode[] = "/0/0/0";
file_t* p = nullptr;
this_t* p = nullptr;
rc_t rc;
if((rc = fileClose(hRef)) != kOkRC )
if((rc = close(hRef)) != kOkRC )
return rc;
if( cwIsFlag(flags,kReadFileFl) )
if( cwIsFlag(flags,kReadFl) )
mode[0] = 'r';
else
if( cwIsFlag(flags,kWriteFileFl) )
if( cwIsFlag(flags,kWriteFl) )
mode[0] = 'w';
else
if( cwIsFlag(flags,kAppendFileFl) )
if( cwIsFlag(flags,kAppendFl) )
mode[0] = 'a';
else
cwLogError(kInvalidArgRC,"File open flags must contain 'kReadFileFl','kWriteFileFl', or 'kAppendFileFl'.");
cwLogError(kInvalidArgRC,"File open flags must contain 'kReadFl','kWriteFl', or 'kAppendFl'.");
if( cwIsFlag(flags,kUpdateFileFl) )
if( cwIsFlag(flags,kUpdateFl) )
mode[1] = '+';
// handle requests to use stdin,stdout,stderr
FILE* sfp = nullptr;
if( cwIsFlag(flags,kStdoutFileFl) )
if( cwIsFlag(flags,kStdoutFl) )
{
sfp = stdout;
fn = "stdout";
}
else
if( cwIsFlag(flags,kStderrFileFl) )
if( cwIsFlag(flags,kStderrFl) )
{
sfp = stderr;
fn = "stderr";
}
else
if( cwIsFlag(flags,kStdinFileFl) )
if( cwIsFlag(flags,kStdinFl) )
{
sfp = stdin;
fn = "stdin";
@ -149,9 +155,9 @@ cw::rc_t cw::fileOpen( fileH_t& hRef, const char* fn, unsigned flags )
if( fn == nullptr )
return cwLogError(kInvalidArgRC,"File object allocation failed due to empty file name.");
unsigned byteCnt = sizeof(file_t) + strlen(fn) + 1;
unsigned byteCnt = sizeof(this_t) + strlen(fn) + 1;
if((p = memAllocZ<file_t>(byteCnt)) == nullptr )
if((p = memAllocZ<this_t>(byteCnt)) == nullptr )
return cwLogError(kOpFailRC,"File object allocation failed for file '%s'.",cwStringNullGuard(fn));
p->fnStr = (char*)(p+1);
@ -175,12 +181,12 @@ cw::rc_t cw::fileOpen( fileH_t& hRef, const char* fn, unsigned flags )
return kOkRC;
}
cw::rc_t cw::fileClose( fileH_t& hRef )
cw::rc_t cw::file::close( handle_t& hRef )
{
if( fileIsValid(hRef) == false )
if( isValid(hRef) == false )
return kOkRC;
file_t* p = _fileHandleToPtr(hRef);
this_t* p = _handleToPtr(hRef);
errno = 0;
if( p->fp != nullptr )
@ -188,17 +194,17 @@ cw::rc_t cw::fileClose( fileH_t& hRef )
return cwLogSysError(kCloseFailRC,errno,"File close failed on '%s'.", cwStringNullGuard(p->fnStr));
memRelease(p);
hRef.set(nullptr);
hRef.clear();
return kOkRC;
}
bool cw::fileIsValid( fileH_t h )
bool cw::file::isValid( handle_t h )
{ return h.isValid(); }
cw::rc_t cw::fileRead( fileH_t h, void* buf, unsigned bufByteCnt )
cw::rc_t cw::file::read( handle_t h, void* buf, unsigned bufByteCnt )
{
file_t* p = _fileHandleToPtr(h);
this_t* p = _handleToPtr(h);
errno = 0;
if( fread(buf,bufByteCnt,1,p->fp) != 1 )
@ -207,9 +213,9 @@ cw::rc_t cw::fileRead( fileH_t h, void* buf, unsigned bufByteCnt )
return kOkRC;
}
cw::rc_t cw::fileWrite( fileH_t h, const void* buf, unsigned bufByteCnt )
cw::rc_t cw::file::write( handle_t h, const void* buf, unsigned bufByteCnt )
{
file_t* p = _fileHandleToPtr(h);
this_t* p = _handleToPtr(h);
errno = 0;
if( fwrite(buf,bufByteCnt,1,p->fp) != 1 )
@ -218,18 +224,18 @@ cw::rc_t cw::fileWrite( fileH_t h, const void* buf, unsigned bufByteCnt )
return kOkRC;
}
cw::rc_t cw::fileSeek( fileH_t h, enum fileSeekFlags_t flags, int offsByteCnt )
cw::rc_t cw::file::seek( handle_t h, enum seekFlags_t flags, int offsByteCnt )
{
file_t* p = _fileHandleToPtr(h);
this_t* p = _handleToPtr(h);
unsigned fileflags = 0;
if( cwIsFlag(flags,kBeginFileFl) )
if( cwIsFlag(flags,kBeginFl) )
fileflags = SEEK_SET;
else
if( cwIsFlag(flags,kCurFileFl) )
if( cwIsFlag(flags,kCurFl) )
fileflags = SEEK_CUR;
else
if( cwIsFlag(flags,kEndFileFl) )
if( cwIsFlag(flags,kEndFl) )
fileflags = SEEK_END;
else
return cwLogError(kInvalidArgRC,"Invalid file seek flag on '%s'.",cwStringNullGuard(p->fnStr));
@ -241,11 +247,11 @@ cw::rc_t cw::fileSeek( fileH_t h, enum fileSeekFlags_t flags, int offsByteCnt
return kOkRC;
}
cw::rc_t cw::fileTell( fileH_t h, long* offsPtr )
cw::rc_t cw::file::tell( handle_t h, long* offsPtr )
{
cwAssert( offsPtr != nullptr );
*offsPtr = -1;
file_t* p = _fileHandleToPtr(h);
this_t* p = _handleToPtr(h);
errno = 0;
if((*offsPtr = ftell(p->fp)) == -1)
@ -254,15 +260,15 @@ cw::rc_t cw::fileTell( fileH_t h, long* offsPtr )
}
bool cw::fileEof( fileH_t h )
{ return feof( _fileHandleToPtr(h)->fp ) != 0; }
bool cw::file::eof( handle_t h )
{ return feof( _handleToPtr(h)->fp ) != 0; }
unsigned cw::fileByteCount( fileH_t h )
unsigned cw::file::byteCount( handle_t h )
{
struct stat sr;
int f;
file_t* p = _fileHandleToPtr(h);
this_t* p = _handleToPtr(h);
const char errMsg[] = "File byte count request failed.";
errno = 0;
@ -282,44 +288,44 @@ unsigned cw::fileByteCount( fileH_t h )
return sr.st_size;
}
cw::rc_t cw::fileByteCountFn( const char* fn, unsigned* fileByteCntPtr )
cw::rc_t cw::file::byteCountFn( const char* fn, unsigned* fileByteCntPtr )
{
cwAssert( fileByteCntPtr != nullptr );
rc_t rc;
fileH_t h;
handle_t h;
if((rc = fileOpen(h,fn,kReadFileFl)) != kOkRC )
if((rc = open(h,fn,kReadFl)) != kOkRC )
return rc;
if( fileByteCntPtr != nullptr)
*fileByteCntPtr = fileByteCount(h);
*fileByteCntPtr = byteCount(h);
fileClose(h);
close(h);
return rc;
}
cw::rc_t cw::fileCompare( const char* fn0, const char* fn1, bool& isEqualRef )
cw::rc_t cw::file::compare( const char* fn0, const char* fn1, bool& isEqualRef )
{
rc_t rc = kOkRC;
unsigned bufByteCnt = 2048;
fileH_t h0;
fileH_t h1;
file_t* p0 = nullptr;
file_t* p1 = nullptr;
handle_t h0;
handle_t h1;
this_t* p0 = nullptr;
this_t* p1 = nullptr;
char b0[ bufByteCnt ];
char b1[ bufByteCnt ];
isEqualRef = true;
if((rc = fileOpen(h0,fn0,kReadFileFl)) != kOkRC )
if((rc = open(h0,fn0,kReadFl)) != kOkRC )
goto errLabel;
if((rc = fileOpen(h1,fn1,kReadFileFl)) != kOkRC )
if((rc = open(h1,fn1,kReadFl)) != kOkRC )
goto errLabel;
p0 = _fileHandleToPtr(h0);
p1 = _fileHandleToPtr(h1);
p0 = _handleToPtr(h0);
p1 = _handleToPtr(h1);
while(1)
{
@ -336,36 +342,36 @@ cw::rc_t cw::fileCompare( const char* fn0, const char* fn1, bool& isEqualRef )
}
errLabel:
fileClose(h0);
fileClose(h1);
close(h0);
close(h1);
return rc;
}
const char* cw::fileName( fileH_t h )
const char* cw::file::name( handle_t h )
{
file_t* p = _fileHandleToPtr(h);
this_t* p = _handleToPtr(h);
return p->fnStr;
}
cw::rc_t cw::fileFnWrite( const char* fn, const void* buf, unsigned bufByteCnt )
cw::rc_t cw::file::fnWrite( const char* fn, const void* buf, unsigned bufByteCnt )
{
fileH_t h;
handle_t h;
rc_t rc;
if((rc = fileOpen(h,fn,kWriteFileFl)) != kOkRC )
if((rc = open(h,fn,kWriteFl)) != kOkRC )
goto errLabel;
rc = fileWrite(h,buf,bufByteCnt);
rc = write(h,buf,bufByteCnt);
errLabel:
fileClose(h);
close(h);
return rc;
}
cw::rc_t cw::fileCopy(
cw::rc_t cw::file::copy(
const char* srcDir,
const char* srcFn,
const char* srcExt,
@ -401,12 +407,12 @@ cw::rc_t cw::fileCopy(
}
// read the source file into a buffer
if((buf = fileFnToBuf(srcPathFn,&byteCnt)) == nullptr )
if((buf = fnToBuf(srcPathFn,&byteCnt)) == nullptr )
rc = cwLogError(kReadFailRC,"Attempt to fill a buffer from '%s' failed.",cwStringNullGuard(srcPathFn));
else
{
// write the file to the output file
if( fileFnWrite(dstPathFn,buf,byteCnt) != kOkRC )
if( fnWrite(dstPathFn,buf,byteCnt) != kOkRC )
rc = cwLogError(kWriteFailRC,"An attempt to write a buffer to '%s' failed.",cwStringNullGuard(dstPathFn));
}
@ -419,7 +425,7 @@ cw::rc_t cw::fileCopy(
}
cw::rc_t cw::fileBackup( const char* dir, const char* name, const char* ext )
cw::rc_t cw::file::backup( const char* dir, const char* name, const char* ext )
{
rc_t rc = kOkRC;
char* newName = nullptr;
@ -465,7 +471,7 @@ cw::rc_t cw::fileBackup( const char* dir, const char* name, const char* ext )
if( fileSysIsFile(newFn) == false )
{
// .. then duplicate the file
if((rc = fileCopy(srcFn,nullptr,nullptr,newFn,nullptr,nullptr)) != kOkRC )
if((rc = copy(srcFn,nullptr,nullptr,newFn,nullptr,nullptr)) != kOkRC )
rc = cwLogError(rc,"The file '%s' could not be duplicated as '%s'.",cwStringNullGuard(srcFn),cwStringNullGuard(newFn));
break;
@ -486,22 +492,22 @@ cw::rc_t cw::fileBackup( const char* dir, const char* name, const char* ext )
}
char* cw::fileToBuf( fileH_t h, unsigned* bufByteCntPtr )
char* cw::file::toBuf( handle_t h, unsigned* bufByteCntPtr )
{ return _fileToBuf(h,0,bufByteCntPtr); }
char* cw::fileFnToBuf( const char* fn, unsigned* bufByteCntPtr )
char* cw::file::fnToBuf( const char* fn, unsigned* bufByteCntPtr )
{ return _fileFnToBuf(fn,0,bufByteCntPtr); }
char* cw::fileToStr( fileH_t h, unsigned* bufByteCntPtr )
char* cw::file::toStr( handle_t h, unsigned* bufByteCntPtr )
{ return _fileToBuf(h,1,bufByteCntPtr); }
char* cw::fileFnToStr( const char* fn, unsigned* bufByteCntPtr )
char* cw::file::fnToStr( const char* fn, unsigned* bufByteCntPtr )
{ return _fileFnToBuf(fn,1,bufByteCntPtr); }
cw::rc_t cw::fileLineCount( fileH_t h, unsigned* lineCntPtr )
cw::rc_t cw::file::lineCount( handle_t h, unsigned* lineCntPtr )
{
rc_t rc = kOkRC;
file_t* p = _fileHandleToPtr(h);
this_t* p = _handleToPtr(h);
unsigned lineCnt = 0;
long offs;
int c;
@ -510,7 +516,7 @@ cw::rc_t cw::fileLineCount( fileH_t h, unsigned* lineCntPtr )
cwAssert( lineCntPtr != nullptr );
*lineCntPtr = 0;
if((rc = fileTell(h,&offs)) != kOkRC )
if((rc = tell(h,&offs)) != kOkRC )
return rc;
errno = 0;
@ -522,7 +528,7 @@ cw::rc_t cw::fileLineCount( fileH_t h, unsigned* lineCntPtr )
if( c == EOF )
{
if( errno )
rc = cwLogSysError(kReadFailRC,errno,"File read char failed on 's'.", cwStringNullGuard(fileName(h)));
rc = cwLogSysError(kReadFailRC,errno,"File read char failed on 's'.", cwStringNullGuard(name(h)));
else
++lineCnt; // add one in case the last line isn't terminated with a '\n'.
@ -535,7 +541,7 @@ cw::rc_t cw::fileLineCount( fileH_t h, unsigned* lineCntPtr )
}
if((rc = fileSeek(h,kBeginFileFl,offs)) != kOkRC )
if((rc = seek(h,kBeginFl,offs)) != kOkRC )
return rc;
*lineCntPtr = lineCnt;
@ -544,10 +550,10 @@ cw::rc_t cw::fileLineCount( fileH_t h, unsigned* lineCntPtr )
}
cw::rc_t cw::fileGetLine( fileH_t h, char* buf, unsigned* bufByteCntPtr )
cw::rc_t cw::file::getLine( handle_t h, char* buf, unsigned* bufByteCntPtr )
{
cwAssert( bufByteCntPtr != nullptr );
file_t* p = _fileHandleToPtr(h);
this_t* p = _handleToPtr(h);
unsigned tn = 128;
char t[ tn ];
unsigned on = *bufByteCntPtr;
@ -555,7 +561,7 @@ cw::rc_t cw::fileGetLine( fileH_t h, char* buf, unsigned* bufByteCntPtr )
rc_t rc;
// store the current file offset
if((rc = fileTell(h,&offs)) != kOkRC )
if((rc = tell(h,&offs)) != kOkRC )
return rc;
// if no buffer was given then use t[]
@ -598,7 +604,7 @@ cw::rc_t cw::fileGetLine( fileH_t h, char* buf, unsigned* bufByteCntPtr )
}
// restore the original file offset
if((rc = fileSeek(h,kBeginFileFl,offs)) != kOkRC )
if((rc = seek(h,kBeginFl,offs)) != kOkRC )
return rc;
// add 1 for /0, 1 for /n and 1 to detect buf-too-short
@ -608,7 +614,7 @@ cw::rc_t cw::fileGetLine( fileH_t h, char* buf, unsigned* bufByteCntPtr )
}
cw::rc_t cw::fileGetLineAuto( fileH_t h, char** bufPtrPtr, unsigned* bufByteCntPtr )
cw::rc_t cw::file::getLineAuto( handle_t h, char** bufPtrPtr, unsigned* bufByteCntPtr )
{
rc_t rc = kOkRC;
bool fl = true;
@ -620,7 +626,7 @@ cw::rc_t cw::fileGetLineAuto( fileH_t h, char** bufPtrPtr, unsigned* bufByteCntP
{
fl = false;
switch( rc = fileGetLine(h,buf,bufByteCntPtr) )
switch( rc = getLine(h,buf,bufByteCntPtr) )
{
case kOkRC:
{
@ -644,91 +650,91 @@ cw::rc_t cw::fileGetLineAuto( fileH_t h, char** bufPtrPtr, unsigned* bufByteCntP
return rc;
}
cw::rc_t cw::fileReadChar( fileH_t h, char* buf, unsigned cnt )
{ return fileRead(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::readChar( handle_t h, char* buf, unsigned cnt )
{ return read(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileReadUChar( fileH_t h, unsigned char* buf, unsigned cnt )
{ return fileRead(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::readUChar( handle_t h, unsigned char* buf, unsigned cnt )
{ return read(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileReadShort( fileH_t h, short* buf, unsigned cnt )
{ return fileRead(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::readShort( handle_t h, short* buf, unsigned cnt )
{ return read(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileReadUShort( fileH_t h, unsigned short* buf, unsigned cnt )
{ return fileRead(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::readUShort( handle_t h, unsigned short* buf, unsigned cnt )
{ return read(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileReadLong( fileH_t h, long* buf, unsigned cnt )
{ return fileRead(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::readLong( handle_t h, long* buf, unsigned cnt )
{ return read(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileReadULong( fileH_t h, unsigned long* buf, unsigned cnt )
{ return fileRead(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::readULong( handle_t h, unsigned long* buf, unsigned cnt )
{ return read(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileReadInt( fileH_t h, int* buf, unsigned cnt )
{ return fileRead(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::readInt( handle_t h, int* buf, unsigned cnt )
{ return read(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileReadUInt( fileH_t h, unsigned int* buf, unsigned cnt )
{ return fileRead(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::readUInt( handle_t h, unsigned int* buf, unsigned cnt )
{ return read(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileReadFloat( fileH_t h, float* buf, unsigned cnt )
{ return fileRead(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::readFloat( handle_t h, float* buf, unsigned cnt )
{ return read(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileReadDouble( fileH_t h, double* buf, unsigned cnt )
{ return fileRead(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::readDouble( handle_t h, double* buf, unsigned cnt )
{ return read(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileReadBool( fileH_t h, bool* buf, unsigned cnt )
{ return fileRead(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::readBool( handle_t h, bool* buf, unsigned cnt )
{ return read(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteChar( fileH_t h, const char* buf, unsigned cnt )
{ return fileWrite(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::writeChar( handle_t h, const char* buf, unsigned cnt )
{ return write(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteUChar( fileH_t h, const unsigned char* buf, unsigned cnt )
{ return fileWrite(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::writeUChar( handle_t h, const unsigned char* buf, unsigned cnt )
{ return write(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteShort( fileH_t h, const short* buf, unsigned cnt )
{ return fileWrite(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::writeShort( handle_t h, const short* buf, unsigned cnt )
{ return write(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteUShort( fileH_t h, const unsigned short* buf, unsigned cnt )
{ return fileWrite(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::writeUShort( handle_t h, const unsigned short* buf, unsigned cnt )
{ return write(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteLong( fileH_t h, const long* buf, unsigned cnt )
{ return fileWrite(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::writeLong( handle_t h, const long* buf, unsigned cnt )
{ return write(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteULong( fileH_t h, const unsigned long* buf, unsigned cnt )
{ return fileWrite(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::writeULong( handle_t h, const unsigned long* buf, unsigned cnt )
{ return write(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteInt( fileH_t h, const int* buf, unsigned cnt )
{ return fileWrite(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::writeInt( handle_t h, const int* buf, unsigned cnt )
{ return write(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteUInt( fileH_t h, const unsigned int* buf, unsigned cnt )
{ return fileWrite(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::writeUInt( handle_t h, const unsigned int* buf, unsigned cnt )
{ return write(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteFloat( fileH_t h, const float* buf, unsigned cnt )
{ return fileWrite(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::writeFloat( handle_t h, const float* buf, unsigned cnt )
{ return write(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteDouble( fileH_t h, const double* buf, unsigned cnt )
{ return fileWrite(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::writeDouble( handle_t h, const double* buf, unsigned cnt )
{ return write(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteBool( fileH_t h, const bool* buf, unsigned cnt )
{ return fileWrite(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::file::writeBool( handle_t h, const bool* buf, unsigned cnt )
{ return write(h,buf,sizeof(buf[0])*cnt); }
cw::rc_t cw::fileWriteStr( fileH_t h, const char* s )
cw::rc_t cw::file::writeStr( handle_t h, const char* s )
{
rc_t rc;
unsigned n = textLength(s);
if((rc = fileWriteUInt(h,&n,1)) != kOkRC )
if((rc = writeUInt(h,&n,1)) != kOkRC )
return rc;
if( n > 0 )
rc = fileWriteChar(h,s,n);
rc = writeChar(h,s,n);
return rc;
}
cw::rc_t cw::fileReadStr( fileH_t h, char** sRef, unsigned maxCharN )
cw::rc_t cw::file::readStr( handle_t h, char** sRef, unsigned maxCharN )
{
unsigned n;
rc_t rc;
@ -741,7 +747,7 @@ cw::rc_t cw::fileReadStr( fileH_t h, char** sRef, unsigned maxCharN )
maxCharN = 16384;
// read the string length
if((rc = fileReadUInt(h,&n,1)) != kOkRC )
if((rc = readUInt(h,&n,1)) != kOkRC )
return rc;
// verify that string isn't too long
@ -754,7 +760,7 @@ cw::rc_t cw::fileReadStr( fileH_t h, char** sRef, unsigned maxCharN )
char* s = memAllocZ<char>(n+1);
// fill the buffer from the file
if((rc = fileReadChar(h,s,n)) != kOkRC )
if((rc = readChar(h,s,n)) != kOkRC )
return rc;
s[n] = 0; // terminate the string
@ -765,33 +771,33 @@ cw::rc_t cw::fileReadStr( fileH_t h, char** sRef, unsigned maxCharN )
}
cw::rc_t cw::filePrint( fileH_t h, const char* text )
cw::rc_t cw::file::print( handle_t h, const char* text )
{
file_t* p = _fileHandleToPtr(h);
this_t* p = _handleToPtr(h);
errno = 0;
if( fputs(text,p->fp) < 0 )
return cwLogSysError(kOpFailRC,errno,"File print failed on '%s'.", cwStringNullGuard(fileName(h)));
return cwLogSysError(kOpFailRC,errno,"File print failed on '%s'.", cwStringNullGuard(name(h)));
return kOkRC;
}
cw::rc_t cw::fileVPrintf( fileH_t h, const char* fmt, va_list vl )
cw::rc_t cw::file::vPrintf( handle_t h, const char* fmt, va_list vl )
{
file_t* p = _fileHandleToPtr(h);
this_t* p = _handleToPtr(h);
if( vfprintf(p->fp,fmt,vl) < 0 )
return cwLogSysError(kOpFailRC,errno,"File print failed on '%s'.", cwStringNullGuard(fileName(h)));
return cwLogSysError(kOpFailRC,errno,"File print failed on '%s'.", cwStringNullGuard(name(h)));
return kOkRC;
}
cw::rc_t cw::filePrintf( fileH_t h, const char* fmt, ... )
cw::rc_t cw::file::printf( handle_t h, const char* fmt, ... )
{
va_list vl;
va_start(vl,fmt);
rc_t rc = fileVPrintf(h,fmt,vl);
rc_t rc = vPrintf(h,fmt,vl);
va_end(vl);
return rc;
}

341
cwFile.h
View File

@ -3,206 +3,209 @@
namespace cw
{
typedef handle<struct file_str> fileH_t;
// Flags for use with fileOpen().
enum fileOpenFlags_t
namespace file
{
kReadFileFl = 0x01, //< Open a file for reading
kWriteFileFl = 0x02, //< Create an empty file for writing
kAppendFileFl = 0x04, //< Open a file for writing at the end of the file.
kUpdateFileFl = 0x08, //< Open a file for reading and writing.
kBinaryFileFl = 0x10, //< Open a file for binary (not text) input/output.
kStdoutFileFl = 0x20, //< Ignore fn use 'stdout'
kStderrFileFl = 0x40, //< Ignore fn use 'stderr'
kStdinFileFl = 0x80, //< Ignore fn use 'stdin'
};
// Open or create a file.
// Equivalent to fopen().
// If *hp was not initalized by an earlier call to fileOpen() then it should
// be set to fileNullHandle prior to calling this function. If *hp is a valid handle
// then it is automatically finalized by an internal call to fileClose() prior to
// being re-iniitalized.
//
// If kStdoutFileFl, kStderrFileFl or kStdinFileFl are set then
// file name argument 'fn' is ignored.
rc_t fileOpen(
fileH_t& hRef, // Pointer to a client supplied fileHandle_t to recieve the handle for the new object.
const char* fn, // The name of the file to open or create.
unsigned flags ); // See fileOpenFlags_t
typedef handle<struct file_str> handle_t;
// Close a file opened with Equivalent to fclose().
rc_t fileClose( fileH_t& hRef );
// Flags for use with fileOpen().
enum openFlags_t
{
kReadFl = 0x01, //< Open a file for reading
kWriteFl = 0x02, //< Create an empty file for writing
kAppendFl = 0x04, //< Open a file for writing at the end of the file.
kUpdateFl = 0x08, //< Open a file for reading and writing.
kBinaryFl = 0x10, //< Open a file for binary (not text) input/output.
kStdoutFl = 0x20, //< Ignore fn use 'stdout'
kStderrFl = 0x40, //< Ignore fn use 'stderr'
kStdinFl = 0x80, //< Ignore fn use 'stdin'
};
// Return true if the file handle is associated with an open file.
bool fileIsValid( fileH_t h );
// Open or create a file.
// Equivalent to fopen().
// If *hp was not initalized by an earlier call to fileOpen() then it should
// be set to fileNullHandle prior to calling this function. If *hp is a valid handle
// then it is automatically finalized by an internal call to fileClose() prior to
// being re-iniitalized.
//
// If kStdoutFl, kStderrFl or kStdinFl are set then
// file name argument 'fn' is ignored.
rc_t open(
handle_t& hRef, // Pointer to a client supplied fileHandle_t to recieve the handle for the new object.
const char* fn, // The name of the file to open or create.
unsigned flags ); // See fileOpenFlags_t
// Read a block bytes from a file. Equivalent to fread().
rc_t fileRead( fileH_t h, void* buf, unsigned bufByteCnt );
// Close a file opened with Equivalent to fclose().
rc_t close( handle_t& hRef );
// Write a block of bytes to a file. Equivalent to fwrite().
rc_t fileWrite( fileH_t h, const void* buf, unsigned bufByteCnt );
// Return true if the file handle is associated with an open file.
bool isValid( handle_t h );
enum fileSeekFlags_t
{
kBeginFileFl = 0x01,
kCurFileFl = 0x02,
kEndFileFl = 0x04
};
// Read a block bytes from a file. Equivalent to fread().
rc_t read( handle_t h, void* buf, unsigned bufByteCnt );
// Set the file position indicator. Equivalent to fseek().
rc_t fileSeek( fileH_t h, enum fileSeekFlags_t flags, int offsByteCnt );
// Write a block of bytes to a file. Equivalent to fwrite().
rc_t write( handle_t h, const void* buf, unsigned bufByteCnt );
// Return the file position indicator. Equivalent to ftell().
rc_t fileTell( fileH_t h, long* offsPtr );
enum seekFlags_t
{
kBeginFl = 0x01,
kCurFl = 0x02,
kEndFl = 0x04
};
// Return true if the file position indicator is at the end of the file.
// Equivalent to feof().
bool fileEof( fileH_t h );
// Set the file position indicator. Equivalent to fseek().
rc_t seek( handle_t h, enum seekFlags_t flags, int offsByteCnt );
// Return the length of the file in bytes
unsigned fileByteCount( fileH_t h );
rc_t fileByteCountFn( const char* fn, unsigned* fileByteCntPtr );
// Return the file position indicator. Equivalent to ftell().
rc_t tell( handle_t h, long* offsPtr );
// Set *isEqualPtr=true if the two files are identical.
rc_t fileCompare( const char* fn0, const char* fn1, bool& isEqualFlRef );
// Return true if the file position indicator is at the end of the file.
// Equivalent to feof().
bool eof( handle_t h );
// Return the file name associated with a file handle.
const char* fileName( fileH_t h );
// Return the length of the file in bytes
unsigned byteCount( handle_t h );
rc_t byteCountFn( const char* fn, unsigned* fileByteCntPtr );
// Write a buffer to a file.
rc_t fileFnWrite( const char* fn, const void* buf, unsigned bufByteCnt );
// Set *isEqualPtr=true if the two files are identical.
rc_t compare( const char* fn0, const char* fn1, bool& isEqualFlRef );
// Allocate and fill a buffer from the file.
// Set *bufByteCntPtr to count of bytes read into the buffer.
// 'bufByteCntPtr' is optional - set it to nullptr if it is not required by the caller.
// It is the callers responsibility to delete the returned buffer with a
// call to cmMemFree()
char* fileToBuf( fileH_t h, unsigned* bufByteCntPtr );
// Return the file name associated with a file handle.
const char* name( handle_t h );
// Same as fileToBuf() but accepts a file name argument.
char* fileFnToBuf( const char* fn, unsigned* bufByteCntPtr );
// Write a buffer to a file.
rc_t fnWrite( const char* fn, const void* buf, unsigned bufByteCnt );
// Allocate and fill a buffer from the file.
// Set *bufByteCntPtr to count of bytes read into the buffer.
// 'bufByteCntPtr' is optional - set it to nullptr if it is not required by the caller.
// It is the callers responsibility to delete the returned buffer with a
// call to cmMemFree()
char* toBuf( handle_t h, unsigned* bufByteCntPtr );
// Same as fileToBuf() but accepts a file name argument.
char* fnToBuf( const char* fn, unsigned* bufByteCntPtr );
// Copy the file named in srcDir/srcFn/srcExt to a file named dstDir/dstFn/dstExt.
// Note that srcExt/dstExt may be set to nullptr if the file extension is included
// in srcFn/dstFn. Likewise srcFn/dstFn may be set to nullptr if the file name
// is included in srcDir/dstDir.
rc_t fileCopy(
const char* srcDir,
const char* srcFn,
const char* srcExt,
const char* dstDir,
const char* dstFn,
const char* dstExt);
// Copy the file named in srcDir/srcFn/srcExt to a file named dstDir/dstFn/dstExt.
// Note that srcExt/dstExt may be set to nullptr if the file extension is included
// in srcFn/dstFn. Likewise srcFn/dstFn may be set to nullptr if the file name
// is included in srcDir/dstDir.
rc_t copy(
const char* srcDir,
const char* srcFn,
const char* srcExt,
const char* dstDir,
const char* dstFn,
const char* dstExt);
// This function creates a backup copy of the file 'fn' by duplicating it into
// a file named fn_#.ext where # is an integer which makes the file name unique.
// The integers chosen with zero and are incremented until an
// unused file name is found in the same directory as 'fn'.
// If the file identified by 'fn' is not found then the function returns quietly.
rc_t fileBackup( const char* dir, const char* name, const char* ext );
// This function creates a backup copy of the file 'fn' by duplicating it into
// a file named fn_#.ext where # is an integer which makes the file name unique.
// The integers chosen with zero and are incremented until an
// unused file name is found in the same directory as 'fn'.
// If the file identified by 'fn' is not found then the function returns quietly.
rc_t backup( const char* dir, const char* name, const char* ext );
// Allocate and fill a zero terminated string from a file.
// Set *bufByteCntPtr to count of bytes read into the buffer.=
// (the buffer memory size is one byte larger to account for the terminating zero)
// 'bufByteCntPtr' is optional - set it to nullptr if it is not required by the caller.
// It is the callers responsibility to delete the returned buffer with a
// call to cmMemFree()
char* fileToStr( fileH_t h, unsigned* bufByteCntPtr );
// Allocate and fill a zero terminated string from a file.
// Set *bufByteCntPtr to count of bytes read into the buffer.=
// (the buffer memory size is one byte larger to account for the terminating zero)
// 'bufByteCntPtr' is optional - set it to nullptr if it is not required by the caller.
// It is the callers responsibility to delete the returned buffer with a
// call to cmMemFree()
char* toStr( handle_t h, unsigned* bufByteCntPtr );
// Same as fileToBuf() but accepts a file name argument.
char* fileFnToStr( const char* fn, unsigned* bufByteCntPtr );
// Same as fileToBuf() but accepts a file name argument.
char* fnToStr( const char* fn, unsigned* bufByteCntPtr );
// Return the count of lines in a file.
rc_t fileLineCount( fileH_t h, unsigned* lineCntPtr );
// Return the count of lines in a file.
rc_t lineCount( handle_t h, unsigned* lineCntPtr );
// Read the next line into buf[bufByteCnt].
// Consider using fileGetLineAuto() as an alternative to this function
// to avoid having to use a buffer with an explicit size.
//
// If buf is not long enough to hold the entire string then
//
// 1. The function returns kFileBufTooSmallRC
// 2. *bufByteCntPtr is set to the size of the required buffer.
// 3. The internal file position is left unchanged.
//
// If the buffer is long enough to hold the entire line then
// *bufByteCntPtr is left unchanged.
// See fileGetLineTest() in cmProcTest.c or fileGetLineAuto()
// in file.c for examples of how to use this function to a
// achieve proper buffer sizing.
rc_t fileGetLine( fileH_t h, char* buf, unsigned* bufByteCntPtr );
// Read the next line into buf[bufByteCnt].
// Consider using fileGetLineAuto() as an alternative to this function
// to avoid having to use a buffer with an explicit size.
//
// If buf is not long enough to hold the entire string then
//
// 1. The function returns kFileBufTooSmallRC
// 2. *bufByteCntPtr is set to the size of the required buffer.
// 3. The internal file position is left unchanged.
//
// If the buffer is long enough to hold the entire line then
// *bufByteCntPtr is left unchanged.
// See fileGetLineTest() in cmProcTest.c or fileGetLineAuto()
// in file.c for examples of how to use this function to a
// achieve proper buffer sizing.
rc_t getLine( handle_t h, char* buf, unsigned* bufByteCntPtr );
// A version of fileGetLine() which eliminates the need to handle buffer
// sizing.
//
// Example usage:
//
// char* buf = nullptr;
// unsigned bufByteCnt = 0;
// while(fileGetLineAuto(h,&buf,&bufByteCnt)==kOkFileRC)
// proc(buf);
// cmMemPtrFree(buf);
//
// On the first call to this function *bufPtrPtr must be set to nullptr and
// *bufByteCntPtr must be set to 0.
// Following the last call to this function call cmMemPtrFree(bufPtrptr)
// to be sure the line buffer is fully released. Note this step is not
// neccessary if the last call does not return kOkFileRC.
rc_t fileGetLineAuto( fileH_t h, char** bufPtrPtr, unsigned* bufByteCntPtr );
// A version of fileGetLine() which eliminates the need to handle buffer
// sizing.
//
// Example usage:
//
// char* buf = nullptr;
// unsigned bufByteCnt = 0;
// while(fileGetLineAuto(h,&buf,&bufByteCnt)==kOkFileRC)
// proc(buf);
// cmMemPtrFree(buf);
//
// On the first call to this function *bufPtrPtr must be set to nullptr and
// *bufByteCntPtr must be set to 0.
// Following the last call to this function call cmMemPtrFree(bufPtrptr)
// to be sure the line buffer is fully released. Note this step is not
// neccessary if the last call does not return kOkFileRC.
rc_t getLineAuto( handle_t h, char** bufPtrPtr, unsigned* bufByteCntPtr );
// Binary Array Reading Functions
// Each of these functions reads a block of binary data from a file.
// The advantage to using these functions over fileRead() is only that they are type specific.
rc_t fileReadChar( fileH_t h, char* buf, unsigned cnt );
rc_t fileReadUChar( fileH_t h, unsigned char* buf, unsigned cnt );
rc_t fileReadShort( fileH_t h, short* buf, unsigned cnt );
rc_t fileReadUShort( fileH_t h, unsigned short* buf, unsigned cnt );
rc_t fileReadLong( fileH_t h, long* buf, unsigned cnt );
rc_t fileReadULong( fileH_t h, unsigned long* buf, unsigned cnt );
rc_t fileReadInt( fileH_t h, int* buf, unsigned cnt );
rc_t fileReadUInt( fileH_t h, unsigned int* buf, unsigned cnt );
rc_t fileReadFloat( fileH_t h, float* buf, unsigned cnt );
rc_t fileReadDouble( fileH_t h, double* buf, unsigned cnt );
rc_t fileReadBool( fileH_t h, bool* buf, unsigned cnt );
// Binary Array Reading Functions
// Each of these functions reads a block of binary data from a file.
// The advantage to using these functions over fileRead() is only that they are type specific.
rc_t readChar( handle_t h, char* buf, unsigned cnt );
rc_t readUChar( handle_t h, unsigned char* buf, unsigned cnt );
rc_t readShort( handle_t h, short* buf, unsigned cnt );
rc_t readUShort( handle_t h, unsigned short* buf, unsigned cnt );
rc_t readLong( handle_t h, long* buf, unsigned cnt );
rc_t readULong( handle_t h, unsigned long* buf, unsigned cnt );
rc_t readInt( handle_t h, int* buf, unsigned cnt );
rc_t readUInt( handle_t h, unsigned int* buf, unsigned cnt );
rc_t readFloat( handle_t h, float* buf, unsigned cnt );
rc_t readDouble( handle_t h, double* buf, unsigned cnt );
rc_t readBool( handle_t h, bool* buf, unsigned cnt );
// Binary Array Writing Functions
// Each of these functions writes an array to a binary file.
// The advantage to using functions rather than fileWrite() is only that they are type specific.
rc_t fileWriteChar( fileH_t h, const char* buf, unsigned cnt );
rc_t fileWriteUChar( fileH_t h, const unsigned char* buf, unsigned cnt );
rc_t fileWriteShort( fileH_t h, const short* buf, unsigned cnt );
rc_t fileWriteUShort( fileH_t h, const unsigned short* buf, unsigned cnt );
rc_t fileWriteLong( fileH_t h, const long* buf, unsigned cnt );
rc_t fileWriteULong( fileH_t h, const unsigned long* buf, unsigned cnt );
rc_t fileWriteInt( fileH_t h, const int* buf, unsigned cnt );
rc_t fileWriteUInt( fileH_t h, const unsigned int* buf, unsigned cnt );
rc_t fileWriteFloat( fileH_t h, const float* buf, unsigned cnt );
rc_t fileWriteDouble( fileH_t h, const double* buf, unsigned cnt );
rc_t fileWriteBool( fileH_t h, const bool* buf, unsigned cnt );
// Binary Array Writing Functions
// Each of these functions writes an array to a binary file.
// The advantage to using functions rather than fileWrite() is only that they are type specific.
rc_t writeChar( handle_t h, const char* buf, unsigned cnt );
rc_t writeUChar( handle_t h, const unsigned char* buf, unsigned cnt );
rc_t writeShort( handle_t h, const short* buf, unsigned cnt );
rc_t writeUShort( handle_t h, const unsigned short* buf, unsigned cnt );
rc_t writeLong( handle_t h, const long* buf, unsigned cnt );
rc_t writeULong( handle_t h, const unsigned long* buf, unsigned cnt );
rc_t writeInt( handle_t h, const int* buf, unsigned cnt );
rc_t writeUInt( handle_t h, const unsigned int* buf, unsigned cnt );
rc_t writeFloat( handle_t h, const float* buf, unsigned cnt );
rc_t writeDouble( handle_t h, const double* buf, unsigned cnt );
rc_t writeBool( handle_t h, const bool* buf, unsigned cnt );
// Write a string to a file as <N> <char0> <char1> ... <char(N-1)>
// where N is the count of characters in the string.
rc_t fileWriteStr( fileH_t h, const char* s );
// Write a string to a file as <N> <char0> <char1> ... <char(N-1)>
// where N is the count of characters in the string.
rc_t writeStr( handle_t h, const char* s );
// Read a string back from a file as written by fileWriteStr().
// Note that the string will by string will be dynamically allocated
// and threfore must eventually be released via cmMemFree().
// If maxCharN is set to zero then the default maximum string
// length is 16384. Note that this limit is used to prevent
// corrupt files from generating excessively long strings.
rc_t fileReadStr( fileH_t h, char** sRef, unsigned maxCharN );
// Formatted Text Output Functions:
// Print formatted text to a file.
rc_t filePrint( fileH_t h, const char* text );
rc_t filePrintf( fileH_t h, const char* fmt, ... );
rc_t fileVPrintf( fileH_t h, const char* fmt, va_list vl );
// Read a string back from a file as written by fileWriteStr().
// Note that the string will by string will be dynamically allocated
// and threfore must eventually be released via cmMemFree().
// If maxCharN is set to zero then the default maximum string
// length is 16384. Note that this limit is used to prevent
// corrupt files from generating excessively long strings.
rc_t readStr( handle_t h, char** sRef, unsigned maxCharN );
// Formatted Text Output Functions:
// Print formatted text to a file.
rc_t print( handle_t h, const char* text );
rc_t printf( handle_t h, const char* fmt, ... );
rc_t vPrintf( handle_t h, const char* fmt, va_list vl );
}
}

View File

@ -532,27 +532,27 @@ cw::rc_t cw::lexSetTextBuffer( lexH_t h, const char* cp, unsigned cn
cw::rc_t cw::lexSetFile( lexH_t h, const char* fn )
{
rc_t rc = kOkRC;
fileH_t fh;
lex_t* p = _lexHandleToPtr(h);
long n = 0;
rc_t rc = kOkRC;
file::handle_t fh;
lex_t* p = _lexHandleToPtr(h);
long n = 0;
assert( fn != nullptr && p != nullptr );
// open the file
if((rc = fileOpen(fh,fn,kReadFileFl)) != kOkRC )
if((rc = file::open(fh,fn,file::kReadFl)) != kOkRC )
return rc;
// seek to the end of the file
if((rc = fileSeek(fh,kEndFileFl,0)) != kOkRC )
if((rc = file::seek(fh,file::kEndFl,0)) != kOkRC )
return rc;
// get the length of the file
if((rc = fileTell(fh,&n)) != kOkRC )
if((rc = file::tell(fh,&n)) != kOkRC )
return rc;
// rewind to the beginning of the file
if((rc = fileSeek(fh,kBeginFileFl,0)) != kOkRC )
if((rc = file::seek(fh,file::kBeginFl,0)) != kOkRC )
return rc;
// allocate the text buffer
@ -563,7 +563,7 @@ cw::rc_t cw::lexSetFile( lexH_t h, const char* fn )
}
// read the file into the buffer
if((rc = fileRead(fh,p->textBuf,n)) != kOkRC )
if((rc = file::read(fh,p->textBuf,n)) != kOkRC )
return rc;
if((rc = _lexSetTextBuffer( p, p->textBuf, n )) != kOkRC )
@ -571,7 +571,7 @@ cw::rc_t cw::lexSetFile( lexH_t h, const char* fn )
errLabel:
// close the file
rc_t rc0 = fileClose(fh);
rc_t rc0 = file::close(fh);
if(rc != kOkRC )
return rc;

View File

@ -93,11 +93,12 @@ namespace cw
return memDuplStr(s1);
}
// s1n is <= s0n
// copy s1[] into s0[]
size_t i=0;
for(; s1[i]; ++i)
s0[i] = s1[i];
s0[i+1] = 0;
s0[i] = 0;
return s0;
}
@ -118,7 +119,7 @@ namespace cw
C buf[ bufN + 1 ];
size_t n = vsnprintf(buf,bufN,fmt,vl1);
size_t n = vsnprintf(buf,bufN+1,fmt,vl1);
cwAssert(n <= bufN);

View File

@ -521,7 +521,7 @@ cw::rc_t cw::objectFromFile( const char* fn, object_t*& objRef )
unsigned bufByteCnt = 0;
char* buf = NULL;
if(( buf = fileFnToStr(fn, &bufByteCnt)) != NULL )
if(( buf = file::fnToStr(fn, &bufByteCnt)) != NULL )
{
rc = objectFromString( buf, objRef );
memRelease(buf);

View File

@ -16,7 +16,9 @@
#include "cwMidi.h"
#include "cwTime.h"
#include "cwMidiPort.h"
#include "cwAudioPort.h"
#include "cwAudioDevice.h"
#include "cwAudioDeviceTest.h"
#include "cwAudioDeviceAlsa.h"
#include "cwAudioBuf.h"
#include <iostream>
@ -126,10 +128,8 @@ void serialPortSrvTest( cw::object_t* cfg, int argc, const char* argv[] ) { cw::
void midiDeviceTest( cw::object_t* cfg, int argc, const char* argv[] ) { cw::midi::device::test();}
void textBufTest( cw::object_t* cfg, int argc, const char* argv[] ) { cw::textBuf::test(); }
void audioBufTest( cw::object_t* cfg, int argc, const char* argv[] ) { cw::audio::buf::test(); }
void audioPortTest( cw::object_t* cfg, int argc, const char* argv[] )
{
cw::audio::device::test( false, argc, argv );
}
void audioDevTest( cw::object_t* cfg, int argc, const char* argv[] ) { cw::audio::device::test( argc, argv ); }
void audioDevAlsaTest( cw::object_t* cfg, int argc, const char* argv[] ) { cw::audio::device::alsa::report(); }
void stubTest( cw::object_t* cfg, int argc, const char* argv[] )
{
@ -168,7 +168,8 @@ int main( int argc, const char* argv[] )
{ "midiDevice", midiDeviceTest },
{ "textBuf", textBufTest },
{ "audioBuf", audioBufTest },
{ "audioPort",audioPortTest },
{ "audioDev",audioDevTest },
{ "audioDevAlsa", audioDevAlsaTest },
{ "stub", stubTest },
{ nullptr, nullptr }
};

View File

@ -1,2 +1,5 @@
export LD_LIBRARY_PATH=~/sdk/libwebsockets/build/out/lib
# restart pulseaudio to free ALSA driver
systemctl --user restart pulseaudio