cwIo.h,cpp, cwIoTest.cpp : Many changes to get an initial working version of audio with a audio meter UI.
This commit is contained in:
parent
469df69857
commit
f123be0323
760
cwIo.cpp
760
cwIo.cpp
@ -57,21 +57,22 @@ namespace cw
|
|||||||
|
|
||||||
typedef struct audioDev_str
|
typedef struct audioDev_str
|
||||||
{
|
{
|
||||||
bool enableFl; //
|
bool enableFl; // True if this device was enabled by the user
|
||||||
char* devName; //
|
const char* label; // User label
|
||||||
unsigned devIdx; //
|
const char* devName; // System device name
|
||||||
unsigned iCbCnt; // Count the audio driver in/out callbacks
|
unsigned devIdx; // AudioDevice interface device index
|
||||||
unsigned oCbCnt; //
|
audioGroup_t* iGroup; // Audio group pointers for this device
|
||||||
audioGroup_t* iGroup; // Audio group points for this device
|
|
||||||
audioGroup_t* oGroup; //
|
audioGroup_t* oGroup; //
|
||||||
audio_group_dev_t* iagd; // audio group device record assoc'd with this
|
audio_group_dev_t* iagd; // Audio group device record assoc'd with this device
|
||||||
audio_group_dev_t* oagd;
|
audio_group_dev_t* oagd; //
|
||||||
} audioDev_t;
|
} audioDev_t;
|
||||||
|
|
||||||
typedef struct io_str
|
typedef struct io_str
|
||||||
{
|
{
|
||||||
std::atomic<bool> quitFl;
|
std::atomic<bool> quitFl;
|
||||||
|
|
||||||
|
time::spec_t t0;
|
||||||
|
|
||||||
cbFunc_t cbFunc;
|
cbFunc_t cbFunc;
|
||||||
void* cbArg;
|
void* cbArg;
|
||||||
|
|
||||||
@ -88,6 +89,9 @@ namespace cw
|
|||||||
audio::device::alsa::handle_t alsaH;
|
audio::device::alsa::handle_t alsaH;
|
||||||
audio::buf::handle_t audioBufH;
|
audio::buf::handle_t audioBufH;
|
||||||
unsigned audioThreadTimeOutMs;
|
unsigned audioThreadTimeOutMs;
|
||||||
|
unsigned audioMeterDevEnabledN;
|
||||||
|
unsigned audioMeterCbPeriodMs;
|
||||||
|
time::spec_t audioMeterNextTime;
|
||||||
|
|
||||||
audioDev_t* audioDevA;
|
audioDev_t* audioDevA;
|
||||||
unsigned audioDevN;
|
unsigned audioDevN;
|
||||||
@ -105,153 +109,11 @@ namespace cw
|
|||||||
io_t* _handleToPtr( handle_t h )
|
io_t* _handleToPtr( handle_t h )
|
||||||
{ return handleToPtr<handle_t,io_t>(h); }
|
{ return handleToPtr<handle_t,io_t>(h); }
|
||||||
|
|
||||||
// Start or stop all the audio devices in p->audioDevA[]
|
|
||||||
rc_t _audioDeviceStartStop( io_t* p, bool startFl )
|
|
||||||
{
|
|
||||||
rc_t rc = kOkRC;
|
|
||||||
|
|
||||||
for(unsigned i=0; i<p->audioDevN; ++i)
|
//----------------------------------------------------------------------------------------------------------
|
||||||
if( p->audioDevA[i].enableFl )
|
//
|
||||||
{
|
// Serial
|
||||||
rc_t rc0 = kOkRC;
|
//
|
||||||
if( startFl )
|
|
||||||
rc0 = audio::device::start( p->audioH, p->audioDevA[i].devIdx );
|
|
||||||
else
|
|
||||||
rc0 = audio::device::stop( p->audioH, p->audioDevA[i].devIdx );
|
|
||||||
|
|
||||||
if(rc0 != kOkRC )
|
|
||||||
rc = cwLogError(rc0,"The audio device: %s failed to %s.", cwStringNullGuard(p->audioDevA[i].devName), startFl ? "start" : "stop");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Release all resource associated with a group-device record.
|
|
||||||
void _audioGroupDestroyDevs( audio_group_dev_t* agd )
|
|
||||||
{
|
|
||||||
while( agd != nullptr )
|
|
||||||
{
|
|
||||||
audio_group_dev_t* agd0 = agd->link;
|
|
||||||
mem::release(agd);
|
|
||||||
agd = agd0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release all resource associated with all audio group records
|
|
||||||
rc_t _audioGroupDestroyAll( io_t* p )
|
|
||||||
{
|
|
||||||
rc_t rc = kOkRC;
|
|
||||||
|
|
||||||
for(unsigned i=0; i<p->audioGroupN; ++i)
|
|
||||||
{
|
|
||||||
audioGroup_t* ag = p->audioGroupA + i;
|
|
||||||
_audioGroupDestroyDevs( ag->msg.iDevL );
|
|
||||||
_audioGroupDestroyDevs( ag->msg.oDevL );
|
|
||||||
mem::release(ag->msg.iBufArray);
|
|
||||||
mem::release(ag->msg.oBufArray);
|
|
||||||
|
|
||||||
mutex::unlock( ag->mutexH );
|
|
||||||
mutex::destroy( ag->mutexH );
|
|
||||||
}
|
|
||||||
|
|
||||||
mem::release(p->audioGroupA);
|
|
||||||
p->audioGroupN = 0;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc_t _audioDestroy( io_t* p )
|
|
||||||
{
|
|
||||||
rc_t rc = kOkRC;
|
|
||||||
|
|
||||||
// stop each device - this will stop the callbacks to _audioDeviceCallback()
|
|
||||||
if((rc = _audioDeviceStartStop(p,false)) != kOkRC )
|
|
||||||
{
|
|
||||||
rc = cwLogError(rc,"Audio device stop failed.");
|
|
||||||
goto errLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if((rc = audio::device::alsa::destroy(p->alsaH)) != kOkRC )
|
|
||||||
{
|
|
||||||
rc = cwLogError(rc,"ALSA sub-system shutdown failed.");
|
|
||||||
goto errLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if((rc = audio::device::destroy(p->audioH)) != kOkRC )
|
|
||||||
{
|
|
||||||
rc = cwLogError(rc,"Audio device sub-system shutdown failed.");
|
|
||||||
goto errLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if((rc = audio::buf::destroy(p->audioBufH)) != kOkRC )
|
|
||||||
{
|
|
||||||
rc = cwLogError(rc,"Audio buffer release failed.");
|
|
||||||
goto errLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((rc = _audioGroupDestroyAll(p)) != kOkRC )
|
|
||||||
{
|
|
||||||
rc = cwLogError(rc,"Audio group release failed.");
|
|
||||||
goto errLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem::free(p->audioDevA);
|
|
||||||
p->audioDevN = 0;
|
|
||||||
|
|
||||||
errLabel:
|
|
||||||
|
|
||||||
if(rc != kOkRC )
|
|
||||||
rc = cwLogError(rc,"Audio sub-system shutdown failed.");
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
rc_t _destroy( io_t* p )
|
|
||||||
{
|
|
||||||
rc_t rc = kOkRC;
|
|
||||||
|
|
||||||
// stop thread callbacks
|
|
||||||
if((rc = thread_mach::destroy(p->threadMachH)) != kOkRC )
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
for(unsigned i=0; i<p->serialN; ++i)
|
|
||||||
serialPortSrv::destroy( p->serialA[i].serialH );
|
|
||||||
|
|
||||||
mem::free(p->serialA);
|
|
||||||
p->serialN = 0;
|
|
||||||
|
|
||||||
// TODO: clean up the audio system more systematically
|
|
||||||
// by first stopping all the devices and then
|
|
||||||
// reversing the creating process.
|
|
||||||
|
|
||||||
_audioDestroy(p);
|
|
||||||
|
|
||||||
midi::device::destroy(p->midiH);
|
|
||||||
|
|
||||||
|
|
||||||
for(unsigned i=0; i<p->uiMapN; ++i)
|
|
||||||
mem::free(const_cast<char*>(p->uiMapA[i].eleName));
|
|
||||||
mem::release(p->uiMapA);
|
|
||||||
p->uiMapN = 0;
|
|
||||||
|
|
||||||
ui::ws::destroy(p->wsUiH);
|
|
||||||
|
|
||||||
// free the cfg object
|
|
||||||
if( p->cfg != nullptr )
|
|
||||||
p->cfg->free();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
mem::release(p);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _serialPortCb( void* arg, const void* byteA, unsigned byteN )
|
void _serialPortCb( void* arg, const void* byteA, unsigned byteN )
|
||||||
{
|
{
|
||||||
@ -366,6 +228,10 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// MIDI
|
||||||
|
//
|
||||||
void _midiCallback( const midi::packet_t* pktArray, unsigned pktCnt )
|
void _midiCallback( const midi::packet_t* pktArray, unsigned pktCnt )
|
||||||
{
|
{
|
||||||
unsigned i,j;
|
unsigned i,j;
|
||||||
@ -403,6 +269,181 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Audio
|
||||||
|
//
|
||||||
|
|
||||||
|
// Start or stop all the audio devices in p->audioDevA[]
|
||||||
|
rc_t _audioDeviceStartStop( io_t* p, bool startFl )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->audioDevN; ++i)
|
||||||
|
if( p->audioDevA[i].enableFl )
|
||||||
|
{
|
||||||
|
rc_t rc0 = kOkRC;
|
||||||
|
if( startFl )
|
||||||
|
rc0 = audio::device::start( p->audioH, p->audioDevA[i].devIdx );
|
||||||
|
else
|
||||||
|
rc0 = audio::device::stop( p->audioH, p->audioDevA[i].devIdx );
|
||||||
|
|
||||||
|
if(rc0 != kOkRC )
|
||||||
|
rc = cwLogError(rc0,"The audio device: %s failed to %s.", cwStringNullGuard(p->audioDevA[i].devName), startFl ? "start" : "stop");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Release all resource associated with a group-device record.
|
||||||
|
void _audioGroupDestroyDevs( audio_group_dev_t* agd )
|
||||||
|
{
|
||||||
|
while( agd != nullptr )
|
||||||
|
{
|
||||||
|
audio_group_dev_t* agd0 = agd->link;
|
||||||
|
mem::release(agd->meterA);
|
||||||
|
mem::release(agd);
|
||||||
|
agd = agd0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release all resource associated with all audio group records
|
||||||
|
rc_t _audioGroupDestroyAll( io_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->audioGroupN; ++i)
|
||||||
|
{
|
||||||
|
audioGroup_t* ag = p->audioGroupA + i;
|
||||||
|
_audioGroupDestroyDevs( ag->msg.iDevL );
|
||||||
|
_audioGroupDestroyDevs( ag->msg.oDevL );
|
||||||
|
mem::release(ag->msg.iBufArray);
|
||||||
|
mem::release(ag->msg.oBufArray);
|
||||||
|
|
||||||
|
mutex::unlock( ag->mutexH ); // the mutex is expected to be locked at this point
|
||||||
|
mutex::destroy( ag->mutexH );
|
||||||
|
}
|
||||||
|
|
||||||
|
mem::release(p->audioGroupA);
|
||||||
|
p->audioGroupN = 0;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _audioDestroy( io_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
// stop each device - this will stop the callbacks to _audioDeviceCallback()
|
||||||
|
if((rc = _audioDeviceStartStop(p,false)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Audio device stop failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if((rc = audio::device::alsa::destroy(p->alsaH)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"ALSA sub-system shutdown failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if((rc = audio::device::destroy(p->audioH)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Audio device sub-system shutdown failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if((rc = audio::buf::destroy(p->audioBufH)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Audio buffer release failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((rc = _audioGroupDestroyAll(p)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Audio group release failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem::free(p->audioDevA);
|
||||||
|
p->audioDevN = 0;
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
|
||||||
|
if(rc != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Audio sub-system shutdown failed.");
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Are either input or output meter enabled on this audio devices.
|
||||||
|
// Set flags to kInFl or kOutput to select inut or output meters.
|
||||||
|
// Set both flags to check if either input or output meters are enabled.
|
||||||
|
bool _audioDeviceIsMeterEnabled( audioDev_t* ad, unsigned flags )
|
||||||
|
{
|
||||||
|
return (cwIsFlag(flags,kInFl ) && ad->iagd!=nullptr && cwIsFlag(ad->iagd->flags,kMeterFl))
|
||||||
|
|| (cwIsFlag(flags,kOutFl) && ad->oagd!=nullptr && cwIsFlag(ad->oagd->flags,kMeterFl));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void _audioGroupDeviceUpdateMeter( io_t* p, audio_group_dev_t* agd, unsigned flags )
|
||||||
|
{
|
||||||
|
for(unsigned i=0; i<agd->chCnt; ++i)
|
||||||
|
agd->meterA[i] = audio::buf::meter( p->audioBufH, agd->devIdx, i, flags + audio::buf::kMeterFl );
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _audioDeviceMeterCallback( io_t* p, audio_group_dev_t* agd )
|
||||||
|
{
|
||||||
|
msg_t m;
|
||||||
|
m.tid = kAudioMeterTId;
|
||||||
|
m.u.audioGroupDev = agd;
|
||||||
|
return p->cbFunc(p->cbArg,&m);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _audioDeviceUpdateMeters( io_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->audioDevN; ++i)
|
||||||
|
{
|
||||||
|
audioDev_t* ad = p->audioDevA + i;
|
||||||
|
|
||||||
|
if( ad->iagd != nullptr && cwIsFlag(ad->iagd->flags,kMeterFl))
|
||||||
|
{
|
||||||
|
_audioGroupDeviceUpdateMeter( p, ad->iagd, audio::buf::kInFl );
|
||||||
|
_audioDeviceMeterCallback( p, ad->iagd );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ad->oagd != nullptr && cwIsFlag(ad->oagd->flags,kMeterFl))
|
||||||
|
{
|
||||||
|
_audioGroupDeviceUpdateMeter( p, ad->oagd, audio::buf::kOutFl );
|
||||||
|
_audioDeviceMeterCallback( p, ad->oagd );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _audioDeviceProcessMeters( io_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
if( time::isGTE(p->t0,p->audioMeterNextTime) )
|
||||||
|
{
|
||||||
|
rc = _audioDeviceUpdateMeters(p);
|
||||||
|
p->audioMeterNextTime = p->t0;
|
||||||
|
time::advanceMs(p->audioMeterNextTime,p->audioMeterCbPeriodMs);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool _audioGroupBufIsReady( io_t* p, audioGroup_t* ag, bool inputFl )
|
bool _audioGroupBufIsReady( io_t* p, audioGroup_t* ag, bool inputFl )
|
||||||
{
|
{
|
||||||
audio_group_dev_t* agd = inputFl ? ag->msg.iDevL : ag->msg.oDevL;
|
audio_group_dev_t* agd = inputFl ? ag->msg.iDevL : ag->msg.oDevL;
|
||||||
@ -417,9 +458,9 @@ namespace cw
|
|||||||
enum { kAudioGroupGetBuf, kAudioGroupAdvBuf };
|
enum { kAudioGroupGetBuf, kAudioGroupAdvBuf };
|
||||||
void _audioGroupProcSampleBufs( io_t* p, audioGroup_t* ag, unsigned processTypeId, unsigned inputFl )
|
void _audioGroupProcSampleBufs( io_t* p, audioGroup_t* ag, unsigned processTypeId, unsigned inputFl )
|
||||||
{
|
{
|
||||||
sample_t** bufArray = inputFl ? ag->msg.iBufArray : ag->msg.oBufArray;
|
sample_t** bufArray = inputFl ? ag->msg.iBufArray : ag->msg.oBufArray;
|
||||||
unsigned bufArrayChCnt = inputFl ? ag->msg.iBufChCnt : ag->msg.oBufChCnt;
|
unsigned bufArrayChCnt = inputFl ? ag->msg.iBufChCnt : ag->msg.oBufChCnt;
|
||||||
audio_group_dev_t* agd = inputFl ? ag->msg.iDevL : ag->msg.oDevL;
|
audio_group_dev_t* agd = inputFl ? ag->msg.iDevL : ag->msg.oDevL;
|
||||||
unsigned audioBufFlags = inputFl ? audio::buf::kInFl : audio::buf::kOutFl;
|
unsigned audioBufFlags = inputFl ? audio::buf::kInFl : audio::buf::kOutFl;
|
||||||
|
|
||||||
unsigned chIdx = 0;
|
unsigned chIdx = 0;
|
||||||
@ -478,23 +519,28 @@ namespace cw
|
|||||||
|
|
||||||
_audioGroupProcSampleBufs( ag->p, ag, kAudioGroupAdvBuf, true );
|
_audioGroupProcSampleBufs( ag->p, ag, kAudioGroupAdvBuf, true );
|
||||||
_audioGroupProcSampleBufs( ag->p, ag, kAudioGroupAdvBuf, false );
|
_audioGroupProcSampleBufs( ag->p, ag, kAudioGroupAdvBuf, false );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a device index return the associated audioDev_t record.
|
// Given a device index return the associated audioDev_t record.
|
||||||
audioDev_t* _audioDeviceIndexToRecd( io_t* p, unsigned devIdx )
|
audioDev_t* _audioDeviceIndexToRecd( io_t* p, unsigned devIdx, bool reportMissingFl=true )
|
||||||
{
|
{
|
||||||
for(unsigned i=0; i<p->audioDevN; ++i)
|
for(unsigned i=0; i<p->audioDevN; ++i)
|
||||||
if( p->audioDevA[i].devIdx == devIdx )
|
if( p->audioDevA[i].devIdx == devIdx )
|
||||||
return p->audioDevA + i;
|
return p->audioDevA + i;
|
||||||
|
|
||||||
|
cwLogError(kInvalidArgRC,"A device with index %i could not be found.",devIdx);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Add a audioGroup pointer to groupA[] and return the new count of elements in the array.
|
// Add an audioGroup pointer to groupA[] and return the new count of elements in the array.
|
||||||
unsigned _audioDeviceUpdateGroupArray( audioGroup_t** groupA, unsigned groupN, unsigned curGroupN, audioGroup_t* ag )
|
unsigned _audioDeviceUpdateGroupArray( audioGroup_t** groupA, unsigned groupN, unsigned curGroupN, audioGroup_t* ag )
|
||||||
{
|
{
|
||||||
if( ag != nullptr )
|
if( ag != nullptr )
|
||||||
@ -535,7 +581,7 @@ namespace cw
|
|||||||
if( audio::buf::isDeviceReady( p->audioBufH, devIdx, audio::buf::kInFl) )
|
if( audio::buf::isDeviceReady( p->audioBufH, devIdx, audio::buf::kInFl) )
|
||||||
{
|
{
|
||||||
// atomic incr - note that the ordering doesn't matter because the update does not control access to any other variables from another thread
|
// atomic incr - note that the ordering doesn't matter because the update does not control access to any other variables from another thread
|
||||||
std::atomic_store_explicit(&ad->iagd->readyCnt, ad->iagd->readyCnt++, std::memory_order_relaxed);
|
std::atomic_store_explicit(&ad->iagd->readyCnt, ad->iagd->readyCnt+1, std::memory_order_relaxed);
|
||||||
curGroupN = _audioDeviceUpdateGroupArray( groupA, groupN, curGroupN, ad->iGroup );
|
curGroupN = _audioDeviceUpdateGroupArray( groupA, groupN, curGroupN, ad->iGroup );
|
||||||
ad->iagd->cbCnt += 1; // update the callback count for this device
|
ad->iagd->cbCnt += 1; // update the callback count for this device
|
||||||
}
|
}
|
||||||
@ -544,7 +590,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
if( audio::buf::isDeviceReady( p->audioBufH, devIdx, audio::buf::kOutFl ) )
|
if( audio::buf::isDeviceReady( p->audioBufH, devIdx, audio::buf::kOutFl ) )
|
||||||
{
|
{
|
||||||
std::atomic_store_explicit(&ad->oagd->readyCnt, ad->oagd->readyCnt++, std::memory_order_relaxed); // atomic incr
|
std::atomic_store_explicit(&ad->oagd->readyCnt, ad->oagd->readyCnt+1, std::memory_order_relaxed); // atomic incr
|
||||||
curGroupN = _audioDeviceUpdateGroupArray( groupA, groupN, curGroupN, ad->oGroup );
|
curGroupN = _audioDeviceUpdateGroupArray( groupA, groupN, curGroupN, ad->oGroup );
|
||||||
ad->oagd->cbCnt += 1;
|
ad->oagd->cbCnt += 1;
|
||||||
}
|
}
|
||||||
@ -561,7 +607,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
// are all devices in this group ready to provide/accept new audio data
|
// are all devices in this group ready to provide/accept new audio data
|
||||||
for(; agd!=nullptr; agd=agd->link)
|
for(; agd!=nullptr; agd=agd->link)
|
||||||
if( std::atomic_load_explicit(&agd->readyCnt, std::memory_order_acquire) > 0 ) // ACQUIRE
|
if( std::atomic_load_explicit(&agd->readyCnt, std::memory_order_acquire) == 0 ) // ACQUIRE
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -584,6 +630,7 @@ namespace cw
|
|||||||
for(unsigned i=0; i<groupN; ++i)
|
for(unsigned i=0; i<groupN; ++i)
|
||||||
{
|
{
|
||||||
audioGroup_t* ag = groupA[i];
|
audioGroup_t* ag = groupA[i];
|
||||||
|
|
||||||
if( _audioGroupIsReady( ag->msg.iDevL ) && _audioGroupIsReady( ag->msg.oDevL ) )
|
if( _audioGroupIsReady( ag->msg.iDevL ) && _audioGroupIsReady( ag->msg.oDevL ) )
|
||||||
{
|
{
|
||||||
// we now know the group is ready and so the ready count maybe decremented on each device
|
// we now know the group is ready and so the ready count maybe decremented on each device
|
||||||
@ -625,6 +672,7 @@ namespace cw
|
|||||||
|
|
||||||
// groupA[] contains the set of groups which may have been made ready during this callback
|
// groupA[] contains the set of groups which may have been made ready during this callback
|
||||||
_audioGroupNotifyIfReady( p, groupA, curGroupN );
|
_audioGroupNotifyIfReady( p, groupA, curGroupN );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -635,9 +683,13 @@ namespace cw
|
|||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
audio_group_dev_t* new_agd = mem::allocZ<audio_group_dev_t>();
|
audio_group_dev_t* new_agd = mem::allocZ<audio_group_dev_t>();
|
||||||
|
|
||||||
new_agd->name = ad->devName;
|
new_agd->label = ad->label;
|
||||||
|
new_agd->devName= ad->devName;
|
||||||
new_agd->devIdx = ad->devIdx;
|
new_agd->devIdx = ad->devIdx;
|
||||||
|
new_agd->flags = inputFl ? kInFl : kOutFl;
|
||||||
new_agd->chCnt = chCnt;
|
new_agd->chCnt = chCnt;
|
||||||
|
new_agd->chIdx = inputFl ? ag->msg.iBufChCnt : ag->msg.oBufChCnt;
|
||||||
|
new_agd->meterA = mem::allocZ<sample_t>(chCnt);
|
||||||
|
|
||||||
audio_group_dev_t*& agd = inputFl ? ag->msg.iDevL : ag->msg.oDevL;
|
audio_group_dev_t*& agd = inputFl ? ag->msg.iDevL : ag->msg.oDevL;
|
||||||
|
|
||||||
@ -700,6 +752,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
if(( rc = node->getv(
|
if(( rc = node->getv(
|
||||||
"enableFl", p->audioGroupA[i].enableFl,
|
"enableFl", p->audioGroupA[i].enableFl,
|
||||||
|
"label", p->audioGroupA[i].msg.label,
|
||||||
"id", p->audioGroupA[i].msg.groupId,
|
"id", p->audioGroupA[i].msg.groupId,
|
||||||
"srate", p->audioGroupA[i].msg.srate,
|
"srate", p->audioGroupA[i].msg.srate,
|
||||||
"dspFrameCnt", p->audioGroupA[i].msg.dspFrameCnt )) != kOkRC )
|
"dspFrameCnt", p->audioGroupA[i].msg.dspFrameCnt )) != kOkRC )
|
||||||
@ -715,6 +768,9 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lock the mutex so that it is already locked when it is used to block the audio thread
|
||||||
|
// This avoids having to use logic in the thread callback to lock it on the first entry
|
||||||
|
// while not locking it on all following entries.
|
||||||
if((rc = mutex::lock(p->audioGroupA[i].mutexH)) != kOkRC )
|
if((rc = mutex::lock(p->audioGroupA[i].mutexH)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"Error locking audio group mutex.");
|
rc = cwLogError(rc,"Error locking audio group mutex.");
|
||||||
@ -784,6 +840,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
if(( rc = node->getv(
|
if(( rc = node->getv(
|
||||||
"enableFl", ad->enableFl,
|
"enableFl", ad->enableFl,
|
||||||
|
"label", ad->label,
|
||||||
"inGroupId", inGroupId,
|
"inGroupId", inGroupId,
|
||||||
"outGroupId", outGroupId,
|
"outGroupId", outGroupId,
|
||||||
"device", ad->devName,
|
"device", ad->devName,
|
||||||
@ -862,14 +919,21 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if( iag != nullptr )
|
if( iag != nullptr )
|
||||||
|
{
|
||||||
if((rc = _audioGroupAddDevice( iag, true, ad, iChCnt )) != kOkRC )
|
if((rc = _audioGroupAddDevice( iag, true, ad, iChCnt )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if( oag != nullptr )
|
if( oag != nullptr )
|
||||||
|
{
|
||||||
if((rc = _audioGroupAddDevice( oag, false, ad, oChCnt )) != kOkRC )
|
if((rc = _audioGroupAddDevice( oag, false, ad, oChCnt )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// set the device group pointers
|
// set the device group pointers
|
||||||
ad->iGroup = iag;
|
ad->iGroup = iag;
|
||||||
ad->oGroup = oag;
|
ad->oGroup = oag;
|
||||||
@ -891,10 +955,10 @@ namespace cw
|
|||||||
audioGroup_t* ag = p->audioGroupA + i;
|
audioGroup_t* ag = p->audioGroupA + i;
|
||||||
|
|
||||||
if( ag->msg.iBufChCnt )
|
if( ag->msg.iBufChCnt )
|
||||||
ag->msg.iBufArray = mem::allocZ<sample_t*>( ag->msg.iBufChCnt );
|
ag->msg.iBufArray = mem::allocZ<sample_t*>( ag->msg.iBufChCnt );
|
||||||
|
|
||||||
if( ag->msg.oBufChCnt )
|
if( ag->msg.oBufChCnt )
|
||||||
ag->msg.oBufArray = mem::allocZ<sample_t*>( ag->msg.oBufChCnt );
|
ag->msg.oBufArray = mem::allocZ<sample_t*>( ag->msg.oBufChCnt );
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -903,7 +967,6 @@ namespace cw
|
|||||||
rc_t _audioDeviceParseConfig( io_t* p, const object_t* cfg )
|
rc_t _audioDeviceParseConfig( io_t* p, const object_t* cfg )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
unsigned meterMs = 50;
|
|
||||||
const object_t* node = nullptr;
|
const object_t* node = nullptr;
|
||||||
|
|
||||||
// get the audio port node
|
// get the audio port node
|
||||||
@ -911,14 +974,14 @@ namespace cw
|
|||||||
return cwLogError(kSyntaxErrorRC,"Unable to locate the 'audio' configuration node.");
|
return cwLogError(kSyntaxErrorRC,"Unable to locate the 'audio' configuration node.");
|
||||||
|
|
||||||
// get the meterMs value
|
// get the meterMs value
|
||||||
if((rc = node->getv("meterMs", meterMs, "threadTimeOutMs", p->audioThreadTimeOutMs )) != kOkRC )
|
if((rc = node->getv("meterMs", p->audioMeterCbPeriodMs, "threadTimeOutMs", p->audioThreadTimeOutMs )) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kSyntaxErrorRC,"Audio 'meterMs' or 'dspFrameCnt' parse failed.");
|
rc = cwLogError(kSyntaxErrorRC,"Audio 'meterMs' or 'dspFrameCnt' parse failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the audio buffer
|
// initialize the audio buffer
|
||||||
if((rc = audio::buf::create( p->audioBufH, audio::device::count(p->audioH), meterMs )) != kOkRC )
|
if((rc = audio::buf::create( p->audioBufH, audio::device::count(p->audioH), p->audioMeterCbPeriodMs )) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"Audio device buffer failed.");
|
rc = cwLogError(rc,"Audio device buffer failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -987,6 +1050,10 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// UI
|
||||||
|
//
|
||||||
|
|
||||||
// This function is called by the websocket with messages comring from a remote UI.
|
// This function is called by the websocket with messages comring from a remote UI.
|
||||||
rc_t _uiCallback( void* cbArg, unsigned wsSessId, ui::opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const ui::value_t* v )
|
rc_t _uiCallback( void* cbArg, unsigned wsSessId, ui::opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const ui::value_t* v )
|
||||||
@ -1063,10 +1130,87 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// IO
|
||||||
|
//
|
||||||
|
|
||||||
|
rc_t _destroy( io_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
// stop thread callbacks
|
||||||
|
if((rc = thread_mach::destroy(p->threadMachH)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->serialN; ++i)
|
||||||
|
serialPortSrv::destroy( p->serialA[i].serialH );
|
||||||
|
|
||||||
|
mem::free(p->serialA);
|
||||||
|
p->serialN = 0;
|
||||||
|
|
||||||
|
// TODO: clean up the audio system more systematically
|
||||||
|
// by first stopping all the devices and then
|
||||||
|
// reversing the creating process.
|
||||||
|
|
||||||
|
_audioDestroy(p);
|
||||||
|
|
||||||
|
midi::device::destroy(p->midiH);
|
||||||
|
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->uiMapN; ++i)
|
||||||
|
mem::free(const_cast<char*>(p->uiMapA[i].eleName));
|
||||||
|
mem::release(p->uiMapA);
|
||||||
|
p->uiMapN = 0;
|
||||||
|
|
||||||
|
ui::ws::destroy(p->wsUiH);
|
||||||
|
|
||||||
|
// free the cfg object
|
||||||
|
if( p->cfg != nullptr )
|
||||||
|
p->cfg->free();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mem::release(p);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _audioDeviceParams( handle_t h, unsigned devIdx, unsigned flags, io_t*& pRef, audioDev_t*& adRef, unsigned& audioBufFlagsRef )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
pRef = _handleToPtr(h);
|
||||||
|
|
||||||
|
if((adRef = _audioDeviceIndexToRecd(pRef,devIdx)) == nullptr )
|
||||||
|
rc = kInvalidArgRC;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
audioBufFlagsRef = 0;
|
||||||
|
if( cwIsFlag(flags,kInFl) )
|
||||||
|
audioBufFlagsRef += audio::buf::kInFl;
|
||||||
|
|
||||||
|
if( cwIsFlag(flags,kOutFl) )
|
||||||
|
audioBufFlagsRef += audio::buf::kOutFl;
|
||||||
|
|
||||||
|
if( cwIsFlag(flags,kEnableFl) )
|
||||||
|
audioBufFlagsRef += audio::buf::kEnableFl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// IO
|
||||||
|
//
|
||||||
|
|
||||||
cw::rc_t cw::io::create(
|
cw::rc_t cw::io::create(
|
||||||
handle_t& h,
|
handle_t& h,
|
||||||
@ -1113,6 +1257,9 @@ cw::rc_t cw::io::create(
|
|||||||
p->cbFunc = cbFunc;
|
p->cbFunc = cbFunc;
|
||||||
p->cbArg = cbArg;
|
p->cbArg = cbArg;
|
||||||
p->quitFl.store(false);
|
p->quitFl.store(false);
|
||||||
|
time::get(p->t0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
h.set(p);
|
h.set(p);
|
||||||
|
|
||||||
@ -1167,11 +1314,14 @@ cw::rc_t cw::io::exec( handle_t h )
|
|||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
io_t* p = _handleToPtr(h);
|
io_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
if( p->wsUiH.isValid() )
|
if( p->wsUiH.isValid() )
|
||||||
rc = ui::ws::exec(p->wsUiH );
|
rc = ui::ws::exec(p->wsUiH );
|
||||||
|
|
||||||
// if the application quit flag is set then signal that the main thread needs to exit
|
time::get(p->t0);
|
||||||
|
|
||||||
|
if( p->audioMeterDevEnabledN )
|
||||||
|
_audioDeviceProcessMeters(p);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -1280,22 +1430,221 @@ cw::rc_t cw::io::midiDeviceSend( handle_t h, unsigned devIdx, unsigned portIdx,
|
|||||||
unsigned cw::io::audioDeviceCount( handle_t h )
|
unsigned cw::io::audioDeviceCount( handle_t h )
|
||||||
{
|
{
|
||||||
io_t* p = _handleToPtr(h);
|
io_t* p = _handleToPtr(h);
|
||||||
return audio::device::count(p->audioH);
|
return p->audioDevN;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned cw::io::audioDeviceLabelToIndex( handle_t h, const char* label )
|
unsigned cw::io::audioDeviceLabelToIndex( handle_t h, const char* label )
|
||||||
{
|
{
|
||||||
io_t* p = _handleToPtr(h);
|
io_t* p = _handleToPtr(h);
|
||||||
return audio::device::labelToIndex(p->audioH,label);
|
for(unsigned i=0; i<p->audioDevN; ++i)
|
||||||
|
if( textCompare(label,p->audioDevA[i].label) == 0 )
|
||||||
|
return p->audioDevA[i].devIdx;
|
||||||
|
|
||||||
|
return kInvalidIdx;
|
||||||
|
//return audio::device::labelToIndex(p->audioH,label);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* cw::io::audioDeviceLabel( handle_t h, unsigned devIdx )
|
const char* cw::io::audioDeviceName( handle_t h, unsigned devIdx )
|
||||||
{
|
{
|
||||||
io_t* p = _handleToPtr(h);
|
io_t* p = _handleToPtr(h);
|
||||||
assert( devIdx < audioDeviceCount(h) );
|
audioDev_t* ad;
|
||||||
return audio::device::label(p->audioH,devIdx);
|
|
||||||
|
if((ad = _audioDeviceIndexToRecd(p, devIdx )) == nullptr )
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return ad->devName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double cw::io::audioDeviceSampleRate( handle_t h, unsigned devIdx )
|
||||||
|
{
|
||||||
|
io_t* p = _handleToPtr(h);
|
||||||
|
return audio::device::sampleRate(p->audioH, devIdx );
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned cw::io::audioDeviceFramesPerCycle( handle_t h, unsigned devIdx )
|
||||||
|
{
|
||||||
|
io_t* p = _handleToPtr(h);
|
||||||
|
audioDev_t* ad;
|
||||||
|
|
||||||
|
if((ad = _audioDeviceIndexToRecd(p, devIdx )) == nullptr )
|
||||||
|
return audio::device::framesPerCycle(p->audioH, devIdx, ad->iGroup != nullptr );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned cw::io::audioDeviceChannelCount( handle_t h, unsigned devIdx, unsigned inOrOutFlag )
|
||||||
|
{
|
||||||
|
io_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
return audio::device::channelCount(p->audioH, devIdx, inOrOutFlag & kInFl );
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::io::audioDeviceEnableMeters( handle_t h, unsigned devIdx, unsigned inOutEnaFlags )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
io_t* p = nullptr;
|
||||||
|
audioDev_t* ad = nullptr;
|
||||||
|
unsigned audioBufFlags = 0;
|
||||||
|
|
||||||
|
if((rc = _audioDeviceParams( h, devIdx, inOutEnaFlags, p, ad, audioBufFlags )) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Enable tone failed.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool enaFl = inOutEnaFlags & kEnableFl;
|
||||||
|
bool enaState0Fl = _audioDeviceIsMeterEnabled(ad, kInFl | kOutFl);
|
||||||
|
|
||||||
|
audioBufFlags += audio::buf::kMeterFl;
|
||||||
|
|
||||||
|
|
||||||
|
if( inOutEnaFlags & kInFl )
|
||||||
|
ad->iagd->flags = cwEnaFlag(ad->iagd->flags,kMeterFl,enaFl);
|
||||||
|
|
||||||
|
if( inOutEnaFlags & kOutFl )
|
||||||
|
ad->oagd->flags = cwEnaFlag(ad->oagd->flags,kMeterFl,enaFl);
|
||||||
|
|
||||||
|
audio::buf::setFlag( p->audioBufH, devIdx, kInvalidIdx, audioBufFlags );
|
||||||
|
|
||||||
|
bool enaState1Fl= _audioDeviceIsMeterEnabled(ad, kInFl | kOutFl);
|
||||||
|
|
||||||
|
if( enaState1Fl and !enaState0Fl )
|
||||||
|
p->audioMeterDevEnabledN += 1;
|
||||||
|
else
|
||||||
|
if( p->audioMeterDevEnabledN > 0 && !enaState1Fl && enaState0Fl )
|
||||||
|
p->audioMeterDevEnabledN -= 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Enable meters failed.");
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const cw::io::sample_t* cw::io::audioDeviceMeters( handle_t h, unsigned devIdx, unsigned& chCntRef, unsigned inOrOutFlag )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
io_t* p = _handleToPtr(h);
|
||||||
|
sample_t* meterA;
|
||||||
|
|
||||||
|
audioDev_t* ad;
|
||||||
|
if((ad = _audioDeviceIndexToRecd(p,devIdx)) == nullptr )
|
||||||
|
rc = kInvalidArgRC;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool inputFl = inOrOutFlag & kInFl;
|
||||||
|
audio_group_dev_t* agd = inputFl ? ad->iagd : ad->oagd;
|
||||||
|
unsigned flags = inputFl ? audio::buf::kInFl : audio::buf::kOutFl;
|
||||||
|
|
||||||
|
if( !cwIsFlag(agd->flags,kMeterFl) )
|
||||||
|
rc = cwLogError(kInvalidArgRC,"The %s meters on device %s are not enabled.", inputFl ? "input" : "output", cwStringNullGuard(ad->label));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_audioGroupDeviceUpdateMeter(p, agd, flags );
|
||||||
|
|
||||||
|
meterA = agd->meterA;
|
||||||
|
chCntRef = agd->chCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Get meters failed.");
|
||||||
|
|
||||||
|
return meterA;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::io::audioDeviceEnableTone( handle_t h, unsigned devIdx, unsigned inOutEnaFlags )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
io_t* p = nullptr;
|
||||||
|
audioDev_t* ad = nullptr;
|
||||||
|
unsigned audioBufFlags = 0;
|
||||||
|
|
||||||
|
if((rc = _audioDeviceParams( h, devIdx, inOutEnaFlags, p, ad, audioBufFlags )) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Enable tone failed.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
audioBufFlags += audio::buf::kToneFl;
|
||||||
|
audio::buf::setFlag( p->audioBufH, devIdx, kInvalidIdx, audioBufFlags );
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::io::audioDeviceToneFlags( handle_t h, unsigned devIdx, unsigned inOrOutFlag, bool* toneFlA, unsigned chCnt )
|
||||||
|
{
|
||||||
|
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
io_t* p = nullptr;
|
||||||
|
audioDev_t* ad = nullptr;
|
||||||
|
unsigned audioBufFlags = 0;
|
||||||
|
|
||||||
|
if((rc = _audioDeviceParams( h, devIdx, inOrOutFlag, p, ad, audioBufFlags )) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Enable tone failed.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
audioBufFlags += audio::buf::kToneFl;
|
||||||
|
audio::buf::toneFlags( p->audioBufH, devIdx, audioBufFlags, toneFlA, chCnt );
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::io::audioDeviceEnableMute( handle_t h, unsigned devIdx, unsigned inOutEnaFlags )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
io_t* p = nullptr;
|
||||||
|
audioDev_t* ad = nullptr;
|
||||||
|
unsigned audioBufFlags = 0;
|
||||||
|
|
||||||
|
if((rc = _audioDeviceParams( h, devIdx, inOutEnaFlags, p, ad, audioBufFlags )) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Enable mute failed.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
audioBufFlags += audio::buf::kMuteFl;
|
||||||
|
audio::buf::setFlag( p->audioBufH, devIdx, kInvalidIdx, audioBufFlags );
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::io::audioDeviceMuteFlags( handle_t h, unsigned devIdx, unsigned inOrOutFlag, bool* muteFlA, unsigned chCnt )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
io_t* p = nullptr;
|
||||||
|
audioDev_t* ad = nullptr;
|
||||||
|
unsigned audioBufFlags = 0;
|
||||||
|
|
||||||
|
if((rc = _audioDeviceParams( h, devIdx, inOrOutFlag, p, ad, audioBufFlags )) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Enable mute failed.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
audioBufFlags += audio::buf::kMuteFl;
|
||||||
|
audio::buf::muteFlags( p->audioBufH, devIdx, audioBufFlags, muteFlA, chCnt );
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::io::audioDeviceSetGain( handle_t h, unsigned devIdx, unsigned inOrOutFlags, double gain )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
io_t* p = nullptr;
|
||||||
|
audioDev_t* ad = nullptr;
|
||||||
|
unsigned audioBufFlags = 0;
|
||||||
|
|
||||||
|
if((rc = _audioDeviceParams( h, devIdx, inOrOutFlags, p, ad, audioBufFlags )) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Set gain failed.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
audio::buf::setGain( p->audioBufH, devIdx, kInvalidIdx, audioBufFlags, gain );
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------
|
||||||
@ -1361,6 +1710,15 @@ unsigned cw::io::uiFindElementUuId( handle_t h, const char* eleName )
|
|||||||
return kInvalidId;
|
return kInvalidId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned cw::io::uiFindElementUuId( handle_t h, unsigned appId )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
ui::handle_t uiH;
|
||||||
|
if((rc = _handleToUiHandle(h,uiH)) == kOkRC )
|
||||||
|
return ui::findElementUuId(uiH, appId );
|
||||||
|
return kInvalidId;
|
||||||
|
}
|
||||||
|
|
||||||
cw::rc_t cw::io::uiCreateFromObject( handle_t h, const object_t* o, unsigned wsSessId, unsigned parentUuId, const char* eleName)
|
cw::rc_t cw::io::uiCreateFromObject( handle_t h, const object_t* o, unsigned wsSessId, unsigned parentUuId, const char* eleName)
|
||||||
{
|
{
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
@ -1541,3 +1899,57 @@ cw::rc_t cw::io::uiRegisterAppIdMap( handle_t h, const ui::appIdMap_t* map, uns
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::io::uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, bool value )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
ui::handle_t uiH;
|
||||||
|
if((rc = _handleToUiHandle(h,uiH)) == kOkRC )
|
||||||
|
rc = ui::sendValueBool(uiH, wsSessId, uuId, value );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::io::uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, int value )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
ui::handle_t uiH;
|
||||||
|
if((rc = _handleToUiHandle(h,uiH)) == kOkRC )
|
||||||
|
rc = ui::sendValueInt(uiH, wsSessId, uuId, value );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::io::uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, unsigned value )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
ui::handle_t uiH;
|
||||||
|
if((rc = _handleToUiHandle(h,uiH)) == kOkRC )
|
||||||
|
rc = ui::sendValueUInt(uiH, wsSessId, uuId, value );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::io::uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, float value )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
ui::handle_t uiH;
|
||||||
|
if((rc = _handleToUiHandle(h,uiH)) == kOkRC )
|
||||||
|
rc = ui::sendValueFloat(uiH, wsSessId, uuId, value );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::io::uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, double value )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
ui::handle_t uiH;
|
||||||
|
if((rc = _handleToUiHandle(h,uiH)) == kOkRC )
|
||||||
|
rc = ui::sendValueDouble(uiH, wsSessId, uuId, value );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::io::uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, const char* value )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
ui::handle_t uiH;
|
||||||
|
if((rc = _handleToUiHandle(h,uiH)) == kOkRC )
|
||||||
|
rc = ui::sendValueString(uiH, wsSessId, uuId, value );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
86
cwIo.h
86
cwIo.h
@ -15,11 +15,22 @@ namespace cw
|
|||||||
|
|
||||||
typedef handle<struct io_str> handle_t;
|
typedef handle<struct io_str> handle_t;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kDisableFl = 0x00,
|
||||||
|
kEnableFl = 0x01,
|
||||||
|
kInFl = 0x02,
|
||||||
|
kOutFl = 0x04,
|
||||||
|
|
||||||
|
kMeterFl = 0x08
|
||||||
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kSerialTId,
|
kSerialTId,
|
||||||
kMidiTId,
|
kMidiTId,
|
||||||
kAudioTId,
|
kAudioTId,
|
||||||
|
kAudioMeterTId,
|
||||||
kSockTid,
|
kSockTid,
|
||||||
kWebSockTId,
|
kWebSockTId,
|
||||||
kUiTId
|
kUiTId
|
||||||
@ -41,21 +52,28 @@ namespace cw
|
|||||||
|
|
||||||
typedef struct audio_group_dev_str
|
typedef struct audio_group_dev_str
|
||||||
{
|
{
|
||||||
const char* name; // Audio device name
|
const char* label; // User label
|
||||||
|
const char* devName; // Audio device name
|
||||||
unsigned devIdx; // Audio device index
|
unsigned devIdx; // Audio device index
|
||||||
|
unsigned flags; // kInFl | kOutFl | kMeterFl
|
||||||
|
unsigned chIdx; // First channel of this device in i/oBufArray
|
||||||
unsigned chCnt; // Count of audio channels on this device
|
unsigned chCnt; // Count of audio channels on this device
|
||||||
unsigned cbCnt; // Count of device driver callbacks
|
unsigned cbCnt; // Count of device driver callbacks
|
||||||
|
sample_t* meterA; // Meter values for this device.
|
||||||
|
|
||||||
std::atomic_uint readyCnt;// Used internally do not read or write.
|
std::atomic_uint readyCnt;// Used internally do not read or write.
|
||||||
|
|
||||||
struct audio_group_dev_str* link; //
|
struct audio_group_dev_str* link; //
|
||||||
} audio_group_dev_t;
|
} audio_group_dev_t;
|
||||||
|
|
||||||
typedef struct audio_msg_str
|
typedef struct audio_msg_str
|
||||||
{
|
{
|
||||||
unsigned groupId; // Unique group id
|
const char* label; // User provided label
|
||||||
|
unsigned groupId; // User provided group id
|
||||||
double srate; // Group sample rate.
|
double srate; // Group sample rate.
|
||||||
unsigned dspFrameCnt; // Count of samples in each buffer pointed to by iBufArray[] and oBufArray[]
|
unsigned dspFrameCnt; // Count of samples in each buffer pointed to by iBufArray[] and oBufArray[]
|
||||||
|
|
||||||
sample_t** iBufArray; // Array of ptrs to buffers of size bufSmpCnt
|
sample_t** iBufArray; // Array of iBufChCnt ptrs to buffers of size bufSmpCnt
|
||||||
unsigned iBufChCnt; // Count of elements in iBufArray[]
|
unsigned iBufChCnt; // Count of elements in iBufArray[]
|
||||||
time::spec_t* iTimeStampPtr; //
|
time::spec_t* iTimeStampPtr; //
|
||||||
audio_group_dev_t* iDevL; // Linked list of input devices which map directly to channels in iBufArray[]
|
audio_group_dev_t* iDevL; // Linked list of input devices which map directly to channels in iBufArray[]
|
||||||
@ -92,11 +110,12 @@ namespace cw
|
|||||||
unsigned tid;
|
unsigned tid;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
serial_msg_t* serial;
|
serial_msg_t* serial;
|
||||||
midi_msg_t* midi;
|
midi_msg_t* midi;
|
||||||
audio_msg_t* audio;
|
audio_msg_t* audio;
|
||||||
socket_msg_t* sock;
|
audio_group_dev_t* audioGroupDev; // audioMeterTId
|
||||||
ui_msg_t ui;
|
socket_msg_t* sock;
|
||||||
|
ui_msg_t ui;
|
||||||
} u;
|
} u;
|
||||||
} msg_t;
|
} msg_t;
|
||||||
|
|
||||||
@ -148,32 +167,19 @@ namespace cw
|
|||||||
// Audio
|
// Audio
|
||||||
//
|
//
|
||||||
|
|
||||||
unsigned audioDeviceCount( handle_t h );
|
unsigned audioDeviceCount( handle_t h );
|
||||||
unsigned audioDeviceLabelToIndex( handle_t h, const char* label );
|
unsigned audioDeviceLabelToIndex( handle_t h, const char* label );
|
||||||
const char* audioDeviceLabel( handle_t h, unsigned devIdx );
|
const char* audioDeviceName( handle_t h, unsigned devIdx );
|
||||||
rc_t audioDeviceSetup(
|
double audioDeviceSampleRate( handle_t h, unsigned devIdx );
|
||||||
handle_t h,
|
unsigned audioDeviceFramesPerCycle( handle_t h, unsigned devIdx );
|
||||||
unsigned devIdx,
|
unsigned audioDeviceChannelCount( handle_t h, unsigned devIdx, unsigned inOrOutFlag );
|
||||||
double srate,
|
rc_t audioDeviceEnableMeters( handle_t h, unsigned devIdx, unsigned inOutEnaFlags );
|
||||||
unsigned framesPerDeviceCycle,
|
const sample_t* audioDeviceMeters( handle_t h, unsigned devIdx, unsigned& chCntRef, unsigned inOrOutFlag );
|
||||||
unsigned devBufBufN,
|
rc_t audioDeviceEnableTone( handle_t h, unsigned devidx, unsigned inOutEnaFlags );
|
||||||
unsigned framesPerDspCycle,
|
rc_t audioDeviceToneFlags( handle_t h, unsigned devIdx, unsigned inOrOutFlag, bool* toneFlA, unsigned chCnt );
|
||||||
unsigned inputFlags,
|
rc_t audioDeviceEnableMute( handle_t h, unsigned devidx, unsigned inOutEnaFlags );
|
||||||
unsigned outputFlags );
|
rc_t audioDeviceMuteFlags( handle_t h, unsigned devIdx, unsigned inOrOutFlag, bool* muteFlA, unsigned chCnt );
|
||||||
|
rc_t audioDeviceSetGain( handle_t h, unsigned devidx, unsigned inOrOutFlags, double gain );
|
||||||
unsigned audioDeviceChannelCount( handle_t h, unsigned devIdx, unsigned dirFl );
|
|
||||||
double audioDeviceSampleRate( handle_t h, unsigned devIdx );
|
|
||||||
unsigned audioDeviceFramesPerCycle( handle_t h, unsigned devIdx );
|
|
||||||
unsigned audioDeviceChannelFlags( handle_t h, unsigned devIdx, unsigned chIdx, unsigned dirFl );
|
|
||||||
rc_t audioDeviceChannelSetFlags(handle_t h, unsigned devidx, unsigned chIdx, unsigned dirFl, unsigned flags );
|
|
||||||
sample_t audioDeviceChannelMeter( handle_t h, unsigned devIdx, unsigned chIdx, unsigned dirFl );
|
|
||||||
rc_t audioDeviceChannelSetGain( handle_t h, unsigned devIdx, unsigned chIdx, unsigned dirFl, double gain );
|
|
||||||
double audioDeviceChannelGain( handle_t h, unsigned devIdx, unsigned chIdx, unsigned dirFl );
|
|
||||||
|
|
||||||
unsigned audioGroupCount( handle_t h );
|
|
||||||
const char* audioGroupLabel( handle_t h, unsigned groupIdx );
|
|
||||||
unsigned audioGroupId( handle_t h, unsigned groupIdx );
|
|
||||||
rc_t audioGroupSetId( handle_t h, unsigned groupIdx, unsigned groupId );
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------
|
||||||
@ -220,6 +226,7 @@ namespace cw
|
|||||||
|
|
||||||
// Return the uuid of the first matching 'eleName'.
|
// Return the uuid of the first matching 'eleName'.
|
||||||
unsigned uiFindElementUuId( handle_t h, const char* eleName );
|
unsigned uiFindElementUuId( handle_t h, const char* eleName );
|
||||||
|
unsigned uiFindElementUuId( handle_t h, unsigned appId );
|
||||||
|
|
||||||
rc_t uiCreateFromObject( handle_t h, const object_t* o, unsigned wsSessId, unsigned parentUuId=kInvalidId, const char* eleName=nullptr);
|
rc_t uiCreateFromObject( handle_t h, const object_t* o, unsigned wsSessId, unsigned parentUuId=kInvalidId, const char* eleName=nullptr);
|
||||||
rc_t uiCreateFromFile( handle_t h, const char* fn, unsigned wsSessId, unsigned parentUuId=kInvalidId);
|
rc_t uiCreateFromFile( handle_t h, const char* fn, unsigned wsSessId, unsigned parentUuId=kInvalidId);
|
||||||
@ -253,9 +260,14 @@ namespace cw
|
|||||||
// Register parent/child/name app id's
|
// Register parent/child/name app id's
|
||||||
rc_t uiRegisterAppIdMap( handle_t h, const ui::appIdMap_t* map, unsigned mapN );
|
rc_t uiRegisterAppIdMap( handle_t h, const ui::appIdMap_t* map, unsigned mapN );
|
||||||
|
|
||||||
// Send a value to the user interface
|
// Send a value from the application to the UI.
|
||||||
template< typename T >
|
rc_t uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, bool value );
|
||||||
rc_t uiValueToUI( handle_t h, unsigned wsSessId, unsigned uuId, const T& value );
|
rc_t uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, int value );
|
||||||
|
rc_t uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, unsigned value );
|
||||||
|
rc_t uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, float value );
|
||||||
|
rc_t uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, double value );
|
||||||
|
rc_t uiSendValue( handle_t h, unsigned wsSessId, unsigned uuId, const char* value );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
138
cwIoTest.cpp
138
cwIoTest.cpp
@ -18,7 +18,7 @@ namespace cw
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
// Resource Based elements
|
// Resource Based elements
|
||||||
kPanelDivId,
|
kPanelDivId = 1000,
|
||||||
kQuitBtnId,
|
kQuitBtnId,
|
||||||
kPanelBtn1Id,
|
kPanelBtn1Id,
|
||||||
kPanelCheck1Id,
|
kPanelCheck1Id,
|
||||||
@ -28,7 +28,20 @@ namespace cw
|
|||||||
kSelId,
|
kSelId,
|
||||||
kOpt1Id,
|
kOpt1Id,
|
||||||
kOpt2Id,
|
kOpt2Id,
|
||||||
kOpt3Id
|
kOpt3Id,
|
||||||
|
|
||||||
|
kInMeterDivId,
|
||||||
|
kOutMeterDivId,
|
||||||
|
kInMeterBaseId = 2000, kInMeterMaxId = 2999,
|
||||||
|
kInGainBaseId = 3000, kInGainMaxId = 3999,
|
||||||
|
kInToneBaseId = 4000, kInToneMaxId = 4999,
|
||||||
|
kInMuteBaseId = 5000, kInMuteMaxId = 5999,
|
||||||
|
kOutMeterBaseId = 6000, kOutMeterMaxId= 6999,
|
||||||
|
kOutGainBaseId = 7000, kOutGainMaxId = 7999,
|
||||||
|
kOutToneBaseId = 8000, kOutToneMaxId = 8999,
|
||||||
|
kOutMuteBaseId = 9000, kOutMuteMaxId = 9999
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Application Id's for the resource based UI elements.
|
// Application Id's for the resource based UI elements.
|
||||||
@ -36,6 +49,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
{ ui::kRootAppId, kPanelDivId, "panelDivId" },
|
{ ui::kRootAppId, kPanelDivId, "panelDivId" },
|
||||||
{ kPanelDivId, kQuitBtnId, "quitBtnId" },
|
{ kPanelDivId, kQuitBtnId, "quitBtnId" },
|
||||||
|
/*
|
||||||
{ kPanelDivId, kPanelBtn1Id, "myBtn1Id" },
|
{ kPanelDivId, kPanelBtn1Id, "myBtn1Id" },
|
||||||
{ kPanelDivId, kPanelCheck1Id, "myCheck1Id" },
|
{ kPanelDivId, kPanelCheck1Id, "myCheck1Id" },
|
||||||
{ kPanelDivId, kPanelBtn2Id, "myBtn2Id" },
|
{ kPanelDivId, kPanelBtn2Id, "myBtn2Id" },
|
||||||
@ -44,7 +58,8 @@ namespace cw
|
|||||||
{ kPanelDivId, kSelId, "mySel" },
|
{ kPanelDivId, kSelId, "mySel" },
|
||||||
{ kSelId, kOpt1Id, "myOpt1" },
|
{ kSelId, kOpt1Id, "myOpt1" },
|
||||||
{ kSelId, kOpt2Id, "myOpt2" },
|
{ kSelId, kOpt2Id, "myOpt2" },
|
||||||
{ kSelId, kOpt3Id, "myOpt3" },
|
{ SelId, kOpt3Id, "myOpt3" },
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned mapN = sizeof(mapA)/sizeof(mapA[0]);
|
unsigned mapN = sizeof(mapA)/sizeof(mapA[0]);
|
||||||
@ -55,9 +70,67 @@ namespace cw
|
|||||||
handle_t ioH;
|
handle_t ioH;
|
||||||
} app_t;
|
} app_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
rc_t _uiCreateMeters( app_t* app, unsigned wsSessId, unsigned chCnt, bool inputFl )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned parentUuId = ui::kRootAppId;
|
||||||
|
unsigned divUuId = kInvalidId;
|
||||||
|
unsigned titleUuId = kInvalidId;
|
||||||
|
const char* title = inputFl ? "Input" : "Output";
|
||||||
|
const char* divEleName = inputFl ? "inMeterId" : "outMeterId";
|
||||||
|
unsigned divAppId = inputFl ? kInMeterDivId : kOutMeterDivId;
|
||||||
|
unsigned baseMeterId = inputFl ? kInMeterBaseId : kOutMeterBaseId;
|
||||||
|
unsigned baseToneId = inputFl ? kInToneBaseId : kOutToneBaseId;
|
||||||
|
unsigned baseMuteId = inputFl ? kInMuteBaseId : kOutMuteBaseId;
|
||||||
|
unsigned baseGainId = inputFl ? kInGainBaseId : kOutGainBaseId;
|
||||||
|
unsigned colUuId;
|
||||||
|
unsigned uuid;
|
||||||
|
|
||||||
|
uiCreateTitle(app->ioH, titleUuId, wsSessId, parentUuId, nullptr, kInvalidId, nullptr, title );
|
||||||
|
uiCreateDiv( app->ioH, divUuId, wsSessId, parentUuId, divEleName, divAppId, "uiRow", nullptr );
|
||||||
|
|
||||||
|
uiCreateDiv( app->ioH, colUuId, wsSessId, divUuId, nullptr, kInvalidId, "uiCol", nullptr );
|
||||||
|
uiCreateTitle(app->ioH, uuid, wsSessId, colUuId, nullptr, kInvalidId, nullptr, "Tone" );
|
||||||
|
uiCreateTitle(app->ioH, uuid, wsSessId, colUuId, nullptr, kInvalidId, nullptr, "Mute" );
|
||||||
|
uiCreateTitle(app->ioH, uuid, wsSessId, colUuId, nullptr, kInvalidId, nullptr, "Gain" );
|
||||||
|
uiCreateTitle(app->ioH, uuid, wsSessId, colUuId, nullptr, kInvalidId, nullptr, "Meter" );
|
||||||
|
|
||||||
|
for(unsigned i=0; i<chCnt; ++i)
|
||||||
|
{
|
||||||
|
unsigned chLabelN = 32;
|
||||||
|
char chLabel[ chLabelN+1 ];
|
||||||
|
snprintf(chLabel,chLabelN,"%i",i+1);
|
||||||
|
|
||||||
|
uiCreateDiv( app->ioH, colUuId, wsSessId, divUuId, nullptr, kInvalidId, "uiCol", chLabel );
|
||||||
|
uiCreateCheck(app->ioH, uuid, wsSessId, colUuId, nullptr, baseToneId + i, "checkClass", nullptr, false );
|
||||||
|
uiCreateCheck(app->ioH, uuid, wsSessId, colUuId, nullptr, baseMuteId + i, "checkClass", nullptr, false );
|
||||||
|
uiCreateNumb( app->ioH, uuid, wsSessId, colUuId, nullptr, baseGainId + i, "floatClass", nullptr, 0.0, 3.0, 0.001, 3, 0 );
|
||||||
|
uiCreateNumb( app->ioH, uuid, wsSessId, colUuId, nullptr, baseMeterId + i, "floatClass", nullptr, -100.0, 100, 1, 2, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _uiCreateMeterPanel( app_t* app, unsigned wsSessId )
|
||||||
|
{
|
||||||
|
unsigned devIdx = audioDeviceLabelToIndex( app->ioH, "main");
|
||||||
|
unsigned iChCnt = audioDeviceChannelCount( app->ioH, devIdx, kInFl);
|
||||||
|
unsigned oChCnt = audioDeviceChannelCount( app->ioH, devIdx, kOutFl);
|
||||||
|
|
||||||
|
_uiCreateMeters( app, wsSessId, iChCnt, true );
|
||||||
|
_uiCreateMeters( app, wsSessId, oChCnt, false );
|
||||||
|
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
rc_t _onUiInit(app_t* app, const ui_msg_t& m )
|
rc_t _onUiInit(app_t* app, const ui_msg_t& m )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
_uiCreateMeterPanel(app,m.wsSessId);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +144,28 @@ namespace cw
|
|||||||
io::stop( app->ioH );
|
io::stop( app->ioH );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( kInMeterBaseId <= m.appId && m.appId < kInMeterMaxId )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
|
||||||
|
if( kInGainBaseId <= m.appId && m.appId < kInGainMaxId )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
|
||||||
|
if( kInToneBaseId <= m.appId && m.appId < kInToneMaxId )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
|
||||||
|
if( kInMuteBaseId <= m.appId && m.appId < kInMuteMaxId )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,17 +228,29 @@ namespace cw
|
|||||||
{
|
{
|
||||||
// the input channel is not disabled
|
// the input channel is not disabled
|
||||||
if( m.iBufArray[i] != NULL )
|
if( m.iBufArray[i] != NULL )
|
||||||
memcpy(m.oBufArray[i], m.iBufArray[i], byteCnt);
|
{
|
||||||
|
for(unsigned j=0; j<m.dspFrameCnt; ++j )
|
||||||
|
m.oBufArray[i][j] = m.iBufArray[i][j];
|
||||||
|
//memcpy(m.oBufArray[i],m.iBufArray[i],byteCnt);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
// the input channel is disabled but the output is not - so fill the output with zeros
|
// the input channel is disabled but the output is not - so fill the output with zeros
|
||||||
memset(m.oBufArray[i], 0, byteCnt);
|
memset(m.oBufArray[i], 0, byteCnt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _audioMeterCb( app_t* app, const audio_group_dev_t* agd )
|
||||||
|
{
|
||||||
|
unsigned baseAppId = cwIsFlag(agd->flags,kInFl) ? kInMeterBaseId : kOutMeterBaseId;
|
||||||
|
for(unsigned i=0; i<agd->chCnt; ++i)
|
||||||
|
uiSendValue( app->ioH, kInvalidId, uiFindElementUuId(app->ioH,baseAppId+i), agd->meterA[i] );
|
||||||
|
return kOkRC;
|
||||||
|
}
|
||||||
|
|
||||||
// The main application callback
|
// The main application callback
|
||||||
rc_t testCb( void* arg, const msg_t* m )
|
rc_t testCb( void* arg, const msg_t* m )
|
||||||
{
|
{
|
||||||
@ -163,6 +270,11 @@ namespace cw
|
|||||||
rc = audioCb(app,*m->u.audio);
|
rc = audioCb(app,*m->u.audio);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kAudioMeterTId:
|
||||||
|
if( m->u.audioGroupDev != nullptr )
|
||||||
|
rc = _audioMeterCb(app,m->u.audioGroupDev);
|
||||||
|
break;
|
||||||
|
|
||||||
case kSockTid:
|
case kSockTid:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -197,10 +309,9 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(unsigned i=0; i<audioDeviceCount(h); ++i)
|
for(unsigned i=0; i<audioDeviceCount(h); ++i)
|
||||||
printf("audio: %s\n", audioDeviceLabel(h,i));
|
printf("audio: %s\n", audioDeviceName(h,i));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +330,17 @@ cw::rc_t cw::io::test( const object_t* cfg )
|
|||||||
cwLogError(rc,"Test app start failed.");
|
cwLogError(rc,"Test app start failed.");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
|
unsigned devIdx = audioDeviceLabelToIndex(app.ioH, "main");
|
||||||
|
if( devIdx == kInvalidIdx )
|
||||||
|
cwLogError(kOpFailRC, "Unable to locate the requested audio device.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
audioDeviceEnableMeters( app.ioH, devIdx, kInFl | kOutFl | kEnableFl );
|
||||||
|
//audioDeviceEnableTone( app.ioH, devIdx, kOutFl | kEnableFl );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
while( !isShuttingDown(app.ioH))
|
while( !isShuttingDown(app.ioH))
|
||||||
{
|
{
|
||||||
exec(app.ioH);
|
exec(app.ioH);
|
||||||
|
Loading…
Reference in New Issue
Block a user