//| Copyright: (C) 2020-2024 Kevin Larke //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file. #include "cwCommon.h" #include "cwLog.h" #include "cwCommonImpl.h" #include "cwTest.h" #include "cwMem.h" #include "cwTime.h" #include "cwObject.h" #include "cwUiDecls.h" #include "cwIo.h" #include "cwIoAudioPanel.h" namespace cw { namespace io { namespace audio_panel { enum { kMaxChCnt = 250 }; enum { kPanelDivAppId, kInMeterDivId, kOutMeterDivId, kInMeterBaseId = 1*kMaxChCnt, kInMeterMaxId = kInMeterBaseId + kMaxChCnt-1, kInGainBaseId = 2*kMaxChCnt, kInGainMaxId = kInGainBaseId + kMaxChCnt-1, kInToneBaseId = 3*kMaxChCnt, kInToneMaxId = kInToneBaseId + kMaxChCnt-1, kInMuteBaseId = 4*kMaxChCnt, kInMuteMaxId = kInMuteBaseId + kMaxChCnt-1, kOutMeterBaseId = 5*kMaxChCnt, kOutMeterMaxId= kOutMeterBaseId + kMaxChCnt-1, kOutGainBaseId = 6*kMaxChCnt, kOutGainMaxId = kOutGainBaseId + kMaxChCnt-1, kOutToneBaseId = 7*kMaxChCnt, kOutToneMaxId = kOutToneBaseId + kMaxChCnt-1, kOutMuteBaseId = 8*kMaxChCnt, kOutMuteMaxId = kOutMuteBaseId + kMaxChCnt-1, kMaxAppId }; typedef struct audio_panel_device_str { unsigned devIdx; // float dfltGain; // unsigned iChCnt; // count of input channels unsigned oChCnt; // count of output channels unsigned baseAppId; // device appId range: baseAppId:baseAppId+kMaxAppId struct audio_panel_device_str* link; } audio_panel_device_t; typedef struct audio_panel_str { io::handle_t ioH; unsigned maxAppId; audio_panel_device_t* devL; } audio_panel_t; audio_panel_t* _handleToPtr( handle_t h ) { return handleToPtr(h); } rc_t _destroy( audio_panel_t* p ) { rc_t rc = kOkRC; mem::release(p); return rc; } audio_panel_device_t* _get_device( audio_panel_t* p, unsigned devIdx ) { audio_panel_device_t* d = p->devL; for(; d!=nullptr; d=d->link) if( d->devIdx == devIdx ) return d; cwLogError(kInvalidArgRC,"The audio meter device with index '%i' was not found. ", devIdx); return nullptr; } audio_panel_device_t* _app_id_to_device( audio_panel_t* p, unsigned appId ) { if( appId == kInvalidId ) return nullptr; audio_panel_device_t* d = p->devL; for(; d!=nullptr; d=d->link) if( d->baseAppId <= appId && appId < d->baseAppId + kMaxAppId ) return d; return nullptr; } rc_t _registerDevice( audio_panel_t* p, unsigned baseAppId, unsigned devIdx, float dfltGain ) { rc_t rc = kOkRC; audio_panel_device_t* d = nullptr; if((rc = audioDeviceEnableMeters( p->ioH, devIdx, kInFl | kOutFl | kEnableFl )) != kOkRC ) goto errLabel; if((rc = audioDeviceEnableTone( p->ioH, devIdx, kOutFl | kEnableFl )) != kOkRC ) goto errLabel; d = mem::allocZ(); d->baseAppId = baseAppId; d->devIdx = devIdx; d->dfltGain = dfltGain; d->iChCnt = audioDeviceChannelCount( p->ioH, devIdx, io::kInFl ); d->oChCnt = audioDeviceChannelCount( p->ioH, devIdx, io::kOutFl ); d->link = p->devL; p->devL = d; p->maxAppId = std::max(baseAppId+kMaxAppId,p->maxAppId); errLabel: if( rc != kOkRC ) rc = cwLogError(rc,"Audio meter device registration failed."); return rc; } rc_t _create_meters( audio_panel_t* p, audio_panel_device_t* d, unsigned wsSessId, unsigned chCnt, bool inputFl ) { rc_t rc = kOkRC; if( chCnt == 0 ) return rc; unsigned parentUuId = ui::kRootAppId; unsigned divUuId = kInvalidId; unsigned titleUuId = kInvalidId; unsigned chanId = 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; uiCreateLabel(p->ioH, titleUuId, parentUuId, nullptr, kInvalidId, chanId, nullptr, title ); uiCreateDiv( p->ioH, divUuId, parentUuId, divEleName, d->baseAppId + divAppId, chanId, "uiRow", nullptr ); uiCreateDiv( p->ioH, colUuId, divUuId, nullptr, kInvalidId, chanId, "uiCol", nullptr ); uiCreateLabel(p->ioH, uuid, colUuId, nullptr, kInvalidId, chanId, nullptr, "Tone" ); uiCreateLabel(p->ioH, uuid, colUuId, nullptr, kInvalidId, chanId, nullptr, "Mute" ); uiCreateLabel(p->ioH, uuid, colUuId, nullptr, kInvalidId, chanId, nullptr, "Gain" ); uiCreateLabel(p->ioH, uuid, colUuId, nullptr, kInvalidId, chanId, nullptr, "Meter" ); for(unsigned i=0; iioH, colUuId, divUuId, nullptr, kInvalidId, kInvalidId, "uiCol", chLabel ); uiCreateCheck(p->ioH, uuid, colUuId, nullptr, d->baseAppId + baseToneId + i, i, "checkClass", nullptr, false ); uiCreateCheck(p->ioH, uuid, colUuId, nullptr, d->baseAppId + baseMuteId + i, i, "checkClass", nullptr, false ); uiCreateNumb( p->ioH, uuid, colUuId, nullptr, d->baseAppId + baseGainId + i, i, "floatClass", nullptr, 0.0, 3.0, 0.001, 3, 0 ); uiCreateNumb( p->ioH, uuid, colUuId, nullptr, d->baseAppId + baseMeterId + i, i, "floatClass", nullptr, -100.0, 100, 1, 2, 0 ); } return rc; } // Called when an new UI connects to the engine. rc_t _uiInit( audio_panel_t* p, const ui_msg_t& m ) { rc_t rc = kOkRC; audio_panel_device_t* d = p->devL; for(; d!=nullptr; d=d->link) { _create_meters( p, d, kInvalidId, d->iChCnt, true ); _create_meters( p, d, kInvalidId, d->oChCnt, false ); } return rc; } // Messages from UI to engine. rc_t _uiValue( audio_panel_t* p, const ui_msg_t& m ) { rc_t rc = kOkRC; audio_panel_device_t* d; if((d = _app_id_to_device(p, m.appId )) != nullptr) { } return rc; } // Request from UI for engine value. rc_t _uiEcho( audio_panel_t* p, const ui_msg_t& m ) { rc_t rc = kOkRC; return rc; } rc_t _uiCb( audio_panel_t* p, const ui_msg_t& m ) { rc_t rc = kOkRC; switch( m.opId ) { case ui::kConnectOpId: //cwLogInfo("IO Test Connect: wsSessId:%i.",m.wsSessId); break; case ui::kDisconnectOpId: //cwLogInfo("IO Test Disconnect: wsSessId:%i.",m.wsSessId); break; case ui::kInitOpId: rc = _uiInit(p,m); break; case ui::kValueOpId: rc = _uiValue(p, m ); break; case ui::kEchoOpId: rc = _uiEcho( p, m ); break; case ui::kIdleOpId: break; case ui::kInvalidOpId: // fall through default: assert(0); break; } return rc; } rc_t _audioMeterCb( audio_panel_t* p, const audio_group_dev_t& agd ) { rc_t rc = kOkRC; audio_panel_device_t* apd; if(( apd = _get_device(p,agd.devIdx)) != nullptr ) { unsigned meterAppId = cwIsFlag(agd.flags,kInFl) ? kInMeterBaseId : kOutMeterBaseId; unsigned chCnt = cwIsFlag(agd.flags,kInFl) ? apd->iChCnt : apd->oChCnt; for(unsigned i=0; ibaseAppId + meterAppId + i; uiSendValue( p->ioH, uiFindElementUuId(p->ioH,appId), agd.meterA[i] ); } return kOkRC; } return rc; } } } } cw::rc_t cw::io::audio_panel::create( handle_t& hRef, io::handle_t ioH, unsigned baseAppId ) { rc_t rc = kOkRC; if((rc = destroy(hRef)) != kOkRC ) return rc; audio_panel_t* p = mem::allocZ(); p->ioH = ioH; // create the audio panels for each audio device for(unsigned i=0; imaxAppId; }