2024-12-01 19:35:24 +00:00
//| Copyright: (C) 2020-2024 Kevin Larke <contact AT larke DOT org>
//| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
2021-08-15 20:07:12 +00:00
# include "cwCommon.h"
# include "cwLog.h"
# include "cwCommonImpl.h"
2024-05-29 16:36:57 +00:00
# include "cwTest.h"
2021-08-15 20:07:12 +00:00
# include "cwMem.h"
# include "cwText.h"
2024-04-22 20:02:40 +00:00
# include "cwNumericConvert.h"
2021-08-15 20:07:12 +00:00
# include "cwObject.h"
2024-04-22 20:02:40 +00:00
2021-08-15 20:07:12 +00:00
# include "cwAudioFile.h"
# include "cwVectOps.h"
# include "cwMtx.h"
2024-04-26 21:05:48 +00:00
# include "cwDspTypes.h" // coeff_t, sample_t, srate_t ...
2024-04-06 20:07:46 +00:00
# include "cwTime.h"
# include "cwMidiDecls.h"
2024-01-13 15:16:37 +00:00
# include "cwFlowDecl.h"
2021-08-15 20:07:12 +00:00
# include "cwFlow.h"
# include "cwFlowTypes.h"
2024-04-22 20:02:40 +00:00
# include "cwFlowNet.h"
2021-08-15 20:07:12 +00:00
# include "cwFlowProc.h"
namespace cw
{
namespace flow
{
typedef struct library_str
{
const char * label ;
class_members_t * members ;
} library_t ;
2024-03-25 14:46:45 +00:00
library_t g_library [ ] = {
2024-09-16 17:43:52 +00:00
{ " user_def_proc " , & user_def_proc : : members } ,
2024-04-22 20:02:40 +00:00
{ " poly " , & poly : : members } ,
2024-04-06 20:07:46 +00:00
{ " midi_in " , & midi_in : : members } ,
{ " midi_out " , & midi_out : : members } ,
2021-12-28 01:25:18 +00:00
{ " audio_in " , & audio_in : : members } ,
{ " audio_out " , & audio_out : : members } ,
2024-04-30 23:58:10 +00:00
{ " audio_file_in " , & audio_file_in : : members } ,
{ " audio_file_out " , & audio_file_out : : members } ,
2021-12-28 01:25:18 +00:00
{ " audio_gain " , & audio_gain : : members } ,
{ " audio_split " , & audio_split : : members } ,
{ " audio_duplicate " , & audio_duplicate : : members } ,
{ " audio_merge " , & audio_merge : : members } ,
{ " audio_mix " , & audio_mix : : members } ,
2024-07-11 15:05:40 +00:00
{ " audio_silence " , & audio_silence : : members } ,
2021-12-28 01:25:18 +00:00
{ " sine_tone " , & sine_tone : : members } ,
{ " pv_analysis " , & pv_analysis : : members } ,
{ " pv_synthesis " , & pv_synthesis : : members } ,
{ " spec_dist " , & spec_dist : : members } ,
{ " compressor " , & compressor : : members } ,
2022-12-05 22:21:54 +00:00
{ " limiter " , & limiter : : members } ,
2021-12-28 01:25:18 +00:00
{ " audio_delay " , & audio_delay : : members } ,
2022-12-05 22:21:54 +00:00
{ " dc_filter " , & dc_filter : : members } ,
2021-12-28 01:25:18 +00:00
{ " balance " , & balance : : members } ,
2023-01-05 12:26:25 +00:00
{ " audio_meter " , & audio_meter : : members } ,
2023-02-26 18:43:14 +00:00
{ " audio_marker " , & audio_marker : : members } ,
2024-04-22 20:02:40 +00:00
{ " xfade_ctl " , & xfade_ctl : : members } ,
2024-07-04 21:02:45 +00:00
{ " poly_voice_ctl " , & poly_voice_ctl : : members } ,
{ " midi_voice " , & midi_voice : : members } ,
2024-08-02 17:35:59 +00:00
{ " piano_voice " , & piano_voice : : members } ,
2024-04-26 21:05:48 +00:00
{ " sample_hold " , & sample_hold : : members } ,
{ " number " , & number : : members } ,
2024-06-04 12:36:10 +00:00
{ " reg " , & reg : : members } ,
2024-04-26 21:05:48 +00:00
{ " timer " , & timer : : members } ,
{ " counter " , & counter : : members } ,
2024-04-30 23:58:10 +00:00
{ " list " , & list : : members } ,
{ " add " , & add : : members } ,
{ " preset " , & preset : : members } ,
2024-05-24 20:37:31 +00:00
{ " print " , & print : : members } ,
2024-07-01 14:33:14 +00:00
{ " halt " , & halt : : members } ,
{ " midi_msg " , & midi_msg : : members } ,
2024-07-08 21:04:22 +00:00
{ " midi_split " , & midi_split : : members } ,
2024-07-03 18:27:08 +00:00
{ " midi_file " , & midi_file : : members } ,
{ " midi_merge " , & midi_merge : : members } ,
2021-08-15 20:07:12 +00:00
{ nullptr , nullptr }
} ;
class_members_t * _find_library_record ( const char * label )
{
2024-03-25 14:46:45 +00:00
for ( library_t * l = g_library ; l - > label ! = nullptr ; + + l )
2021-08-15 20:07:12 +00:00
if ( textCompare ( l - > label , label ) = = 0 )
return l - > members ;
return nullptr ;
}
flow_t * _handleToPtr ( handle_t h )
{ return handleToPtr < handle_t , flow_t > ( h ) ; }
2022-12-17 13:16:21 +00:00
rc_t _is_var_flag_set ( const object_t * var_flags_obj , const char * flag_label , const char * classLabel , const char * varLabel , bool & is_set_flag_ref )
{
rc_t rc = kOkRC ;
is_set_flag_ref = false ;
if ( var_flags_obj ! = nullptr )
{
for ( unsigned k = 0 ; k < var_flags_obj - > child_count ( ) ; + + k )
{
const object_t * tag_obj = var_flags_obj - > child_ele ( k ) ;
const char * tag = nullptr ;
if ( tag_obj ! = nullptr & & tag_obj - > is_string ( ) & & ( rc = tag_obj - > value ( tag ) ) = = kOkRC & & tag ! = nullptr )
{
if ( strcmp ( tag , flag_label ) = = 0 )
is_set_flag_ref = true ;
}
else
{
rc = cwLogError ( kSyntaxErrorRC , " An invalid or non-string value was found in a flow class '%s' variable:'%s' 'flags' field. " , classLabel , varLabel ) ;
}
}
}
return rc ;
}
2024-05-06 19:47:13 +00:00
2024-09-16 17:43:52 +00:00
rc_t _parse_udp_var_proxy_string ( const char * proxyStr , var_desc_t * var_desc )
2024-05-06 19:47:13 +00:00
{
rc_t rc = kOkRC ;
const char * period ;
// find the separating period
if ( ( period = firstMatchChar ( proxyStr , ' . ' ) ) = = nullptr )
{
rc = cwLogError ( kSyntaxErrorRC , " The separating '.' could not be found in the proxy string '%s'. " , cwStringNullGuard ( proxyStr ) ) ;
goto errLabel ;
}
// validate the length of the proc inst label
if ( period - proxyStr = = 0 )
{
rc = cwLogError ( kSyntaxErrorRC , " No proxy proc instance was found in the proxy string '%s'. " , cwStringNullGuard ( proxyStr ) ) ;
goto errLabel ;
}
// validate the length of the var label
if ( textLength ( period + 1 ) = = 0 )
{
rc = cwLogError ( kSyntaxErrorRC , " No proxy var was found in the proxy string '%s'. " , cwStringNullGuard ( proxyStr ) ) ;
goto errLabel ;
}
var_desc - > proxyProcLabel = mem : : duplStr ( proxyStr , period - proxyStr ) ;
var_desc - > proxyVarLabel = mem : : duplStr ( period + 1 ) ;
errLabel :
return rc ;
}
rc_t _parse_class_var_attribute_flags ( const object_t * var_flags_obj , unsigned & flags_ref )
{
rc_t rc = kOkRC ;
unsigned result_flags = 0 ;
flags_ref = 0 ;
if ( ! var_flags_obj - > is_list ( ) )
{
rc = cwLogError ( kSyntaxErrorRC , " The variable description 'flags' field must be a list. " ) ;
goto errLabel ;
}
for ( unsigned i = 0 ; i < var_flags_obj - > child_count ( ) ; + + i )
{
const object_t * flag_obj = var_flags_obj - > child_ele ( i ) ;
const char * flag_label = nullptr ;
unsigned flag = 0 ;
// validate the flag syntax
if ( flag_obj = = nullptr | | ! flag_obj - > is_string ( ) | | flag_obj - > value ( flag_label ) ! = kOkRC )
{
rc = cwLogError ( kSyntaxErrorRC , " Invalid variable description flag syntax on flag index %i. " , i ) ;
goto errLabel ;
}
// parse the flag
if ( ( flag = var_desc_attr_label_to_flag ( flag_label ) ) = = kInvalidVarDescFl )
{
rc = cwLogError ( kInvalidArgRC , " The variable description flag ('%s') at flag index %i is not valid. " , cwStringNullGuard ( flag_label ) , i ) ;
goto errLabel ;
}
result_flags | = flag ;
}
flags_ref = result_flags ;
errLabel :
return rc ;
}
rc_t _parse_class_var_cfg ( flow_t * p , class_desc_t * class_desc , const object_t * var_desc_pair , var_desc_t * & var_desc_ref )
{
rc_t rc = kOkRC ;
const object_t * var_flags_obj = nullptr ;
const char * var_value_type_str = nullptr ;
const char * var_label = nullptr ;
const char * proxy_string = nullptr ;
var_desc_t * vd = nullptr ;
var_desc_ref = nullptr ;
if ( var_desc_pair = = nullptr | | ! var_desc_pair - > is_pair ( ) | | var_desc_pair - > pair_label ( ) = = nullptr | | ( var_label = var_desc_pair - > pair_label ( ) ) = = nullptr | | var_desc_pair - > pair_value ( ) = = nullptr | | ! var_desc_pair - > pair_value ( ) - > is_dict ( ) )
{
rc = cwLogError ( kSyntaxErrorRC , " An invalid variable description syntax was encountered. " ) ;
goto errLabel ;
}
// Allocate the var. desc record
if ( ( vd = var_desc_create ( var_label , var_desc_pair - > pair_value ( ) ) ) = = nullptr )
{
rc = cwLogError ( kObjAllocFailRC , " Variable description allocation failed. " ) ;
goto errLabel ;
}
// get the variable description
if ( ( rc = vd - > cfg - > getv ( " doc " , vd - > docText ) ) ! = kOkRC )
{
rc = cwLogError ( rc , " Parsing failed on class:%s variable: '%s'. " , class_desc - > label , vd - > label ) ;
goto errLabel ;
}
// get the variable description
if ( ( rc = vd - > cfg - > getv_opt ( " flags " , var_flags_obj ,
" type " , var_value_type_str ,
" value " , vd - > val_cfg ,
" proxy " , proxy_string ) ) ! = kOkRC )
{
rc = cwLogError ( rc , " Parsing optional fields failed. " ) ;
goto errLabel ;
}
// convert the type string to a numeric type flag
if ( var_value_type_str ! = nullptr )
if ( ( vd - > type = value_type_label_to_flag ( var_value_type_str ) ) = = kInvalidTId )
{
rc = cwLogError ( kSyntaxErrorRC , " Invalid variable description type flag: '%s' was encountered. " , var_value_type_str ) ;
goto errLabel ;
}
// parse the proxy string into it's two parts: <proc>.<var>
if ( proxy_string ! = nullptr )
{
2024-09-16 17:43:52 +00:00
if ( ( rc = _parse_udp_var_proxy_string ( proxy_string , vd ) ) ! = kOkRC )
2024-05-06 19:47:13 +00:00
goto errLabel ;
}
// parse the var desc attribute flags
if ( var_flags_obj ! = nullptr )
{
vd - > flags = 0 ;
if ( ( rc = _parse_class_var_attribute_flags ( var_flags_obj , vd - > flags ) ) ! = kOkRC )
goto errLabel ;
}
var_desc_ref = vd ;
errLabel :
if ( rc ! = kOkRC )
{
rc = cwLogError ( rc , " A variable description create failed on class desc:'%s' var:'%s'. " , cwStringNullGuard ( class_desc - > label ) , cwStringNullGuard ( var_label ) ) ;
var_desc_destroy ( vd ) ;
}
return rc ;
}
2024-10-12 19:29:39 +00:00
rc_t _create_class_ui_desc ( class_desc_t * desc )
{
desc - > ui = mem : : allocZ < ui_proc_desc_t > ( ) ;
desc - > ui - > label = desc - > label ;
for ( class_preset_t * p0 = desc - > presetL ; p0 ! = nullptr ; p0 = p0 - > link )
desc - > ui - > presetN + = 1 ;
desc - > ui - > presetA = mem : : allocZ < ui_preset_t > ( desc - > ui - > presetN ) ;
unsigned i = 0 ;
for ( class_preset_t * p0 = desc - > presetL ; i < desc - > ui - > presetN ; + + i , p0 = p0 - > link )
{
desc - > ui - > presetA [ i ] . label = p0 - > label ;
desc - > ui - > presetA [ i ] . preset_idx = i ;
}
return kOkRC ;
}
2022-12-17 13:16:21 +00:00
2024-03-25 14:46:45 +00:00
rc_t _parse_class_cfg ( flow_t * p , const object_t * classCfg )
2021-08-15 20:07:12 +00:00
{
rc_t rc = kOkRC ;
if ( ! classCfg - > is_dict ( ) )
return cwLogError ( kSyntaxErrorRC , " The class description dictionary does not have dictionary syntax. " ) ;
p - > classDescN = classCfg - > child_count ( ) ;
p - > classDescA = mem : : allocZ < class_desc_t > ( p - > classDescN ) ;
// for each class description
for ( unsigned i = 0 ; i < p - > classDescN ; + + i )
{
const object_t * class_obj = classCfg - > child_ele ( i ) ;
const object_t * varD = nullptr ;
const object_t * presetD = nullptr ;
class_desc_t * cd = p - > classDescA + i ;
cd - > cfg = class_obj - > pair_value ( ) ;
cd - > label = class_obj - > pair_label ( ) ;
// get the variable description
if ( ( rc = cd - > cfg - > getv_opt ( " vars " , varD ,
2024-04-22 20:02:40 +00:00
" presets " , presetD ,
" poly_limit_cnt " , cd - > polyLimitN ) ) ! = kOkRC )
2021-08-15 20:07:12 +00:00
{
rc = cwLogError ( rc , " Parsing failed while parsing class desc:'%s' " , cwStringNullGuard ( cd - > label ) ) ;
goto errLabel ;
}
// parse the preset dictionary
if ( presetD ! = nullptr )
{
if ( ! presetD - > is_dict ( ) )
{
rc = cwLogError ( rc , " The preset dictionary is not a dictionary on class desc:'%s' " , cwStringNullGuard ( cd - > label ) ) ;
goto errLabel ;
}
// for each preset in the class desc.
for ( unsigned j = 0 ; j < presetD - > child_count ( ) ; + + j )
{
const object_t * pair = presetD - > child_ele ( j ) ;
if ( ! pair - > pair_value ( ) - > is_dict ( ) )
{
rc = cwLogError ( kSyntaxErrorRC , " The preset '%s' in class desc '%s' is not a dictionary. " , cwStringNullGuard ( pair - > pair_label ( ) ) , cwStringNullGuard ( cd - > label ) ) ;
goto errLabel ;
}
2024-05-19 19:24:33 +00:00
class_preset_t * preset = mem : : allocZ < class_preset_t > ( ) ;
2021-08-15 20:07:12 +00:00
preset - > label = pair - > pair_label ( ) ;
preset - > cfg = pair - > pair_value ( ) ;
preset - > link = cd - > presetL ;
cd - > presetL = preset ;
}
}
2024-10-12 19:29:39 +00:00
// create the class descripiton
if ( ( rc = _create_class_ui_desc ( cd ) ) ! = kOkRC )
{
cwLogError ( rc , " Class desc UI record create failed on '%s'. " , cwStringNullGuard ( cd - > label ) ) ;
goto errLabel ;
}
2021-08-15 20:07:12 +00:00
2021-08-23 02:41:33 +00:00
// parse the variable dictionary
2021-08-15 20:07:12 +00:00
if ( varD ! = nullptr )
{
if ( ! varD - > is_dict ( ) )
{
rc = cwLogError ( rc , " The value dictionary is not a dictionary on class desc:'%s' " , cwStringNullGuard ( cd - > label ) ) ;
goto errLabel ;
}
// get the class member functions
if ( ( cd - > members = _find_library_record ( cd - > label ) ) = = nullptr )
{
2024-05-05 21:31:42 +00:00
rc = cwLogError ( kSyntaxErrorRC , " The '%s' class member function record could not be found. " , cd - > label ) ;
2021-08-15 20:07:12 +00:00
goto errLabel ;
}
// for each class value description
for ( unsigned j = 0 ; j < varD - > child_count ( ) ; + + j )
{
2024-05-06 19:47:13 +00:00
const object_t * var_obj = varD - > child_ele ( j ) ;
var_desc_t * vd = nullptr ;
if ( ( rc = _parse_class_var_cfg ( p , cd , var_obj , vd ) ) ! = kOkRC )
2021-08-15 20:07:12 +00:00
{
2024-05-06 19:47:13 +00:00
rc = cwLogError ( rc , " Variable description created failed on the class desc '%s' on the variable description at index '%i'. " , cwStringNullGuard ( cd - > label ) , j ) ;
2021-08-15 20:07:12 +00:00
goto errLabel ;
}
2024-05-06 19:47:13 +00:00
if ( vd - > type = = kInvalidTFl )
2021-08-15 20:07:12 +00:00
{
2024-05-06 19:47:13 +00:00
rc = cwLogError ( rc , " The variable description '%s' in class description '%s' does not have a valid 'type' field. " , cwStringNullGuard ( vd - > label ) , cwStringNullGuard ( cd - > label ) ) ;
goto errLabel ;
2021-08-15 20:07:12 +00:00
}
2024-05-06 19:47:13 +00:00
if ( vd - > proxyProcLabel ! = nullptr | | vd - > proxyVarLabel ! = nullptr )
2021-08-15 20:07:12 +00:00
{
2024-09-16 17:43:52 +00:00
cwLogWarning ( " The 'proxy' field in the variable description '%s' on class description '%s' will be ignored because the variable is not part of a UDP definition. " , cwStringNullGuard ( vd - > label ) , cwStringNullGuard ( cd - > label ) ) ;
2021-08-15 20:07:12 +00:00
}
2022-12-17 13:16:21 +00:00
2024-09-16 17:43:52 +00:00
if ( cwIsFlag ( vd - > flags , kUdpOutVarDescFl ) )
2024-05-06 19:47:13 +00:00
{
2024-09-16 17:43:52 +00:00
cwLogWarning ( " The 'out' flag in the variable description '%s' on class description '%s' will be ignored because the variable is not part of a UDP definition. " , cwStringNullGuard ( vd - > label ) , cwStringNullGuard ( cd - > label ) ) ;
2024-05-06 19:47:13 +00:00
}
2021-08-15 20:07:12 +00:00
vd - > link = cd - > varDescL ;
cd - > varDescL = vd ;
}
}
}
errLabel :
return rc ;
}
2024-09-16 17:43:52 +00:00
rc_t _find_udp_proc_class_desc ( flow_t * p , const object_t * udpProcD , const char * procInstLabel , const class_desc_t * & class_desc_ref )
2021-12-30 02:52:46 +00:00
{
2024-05-05 21:31:42 +00:00
rc_t rc = kOkRC ;
const object_t * procInstD = nullptr ;
const object_t * classStr = nullptr ;
const char * class_label = nullptr ;
2021-08-15 20:07:12 +00:00
2024-05-05 21:31:42 +00:00
class_desc_ref = nullptr ;
2021-08-15 20:07:12 +00:00
2024-09-16 17:43:52 +00:00
// find the proc inst dict in the UDP
if ( ( procInstD = udpProcD - > find_child ( procInstLabel ) ) = = nullptr )
2021-08-15 20:07:12 +00:00
{
2024-09-16 17:43:52 +00:00
rc = cwLogError ( kSyntaxErrorRC , " The proc instance '%s' from the proxy var list could not be foud in the UDP. " , cwStringNullGuard ( procInstLabel ) ) ;
2021-08-15 20:07:12 +00:00
goto errLabel ;
}
2024-05-05 21:31:42 +00:00
// find the proc class label of the proc inst
if ( ( classStr = procInstD - > find_child ( " class " ) ) = = nullptr | | ( rc = classStr - > value ( class_label ) ) ! = kOkRC )
2021-08-15 20:07:12 +00:00
{
2024-05-05 21:31:42 +00:00
rc = cwLogError ( kSyntaxErrorRC , " The 'class' field could not be found in the '%s' proc instance record. " , cwStringNullGuard ( procInstLabel ) ) ;
2021-08-15 20:07:12 +00:00
goto errLabel ;
}
2024-05-05 21:31:42 +00:00
// find the associated class desc record
if ( ( class_desc_ref = class_desc_find ( p , class_label ) ) = = nullptr )
2021-12-28 01:25:18 +00:00
{
2024-05-05 21:31:42 +00:00
rc = cwLogError ( kEleNotFoundRC , " The class desc record '%s' for the proc instance '%s' could not be found. " , class_label , cwStringNullGuard ( procInstLabel ) ) ;
2021-12-28 01:25:18 +00:00
goto errLabel ;
}
2021-08-15 20:07:12 +00:00
errLabel :
2024-05-05 21:31:42 +00:00
2021-08-15 20:07:12 +00:00
return rc ;
}
2024-09-16 17:43:52 +00:00
rc_t _create_udp_var_desc ( flow_t * p , class_desc_t * udpClassDesc , const object_t * udpProcD , const object_t * varDescPair , var_desc_t * & vd_ref )
2021-08-15 20:07:12 +00:00
{
2024-05-05 21:31:42 +00:00
rc_t rc = kOkRC ;
const class_desc_t * proxy_class_desc = nullptr ;
const var_desc_t * proxy_var_desc = nullptr ;
2024-05-06 19:47:13 +00:00
var_desc_t * var_desc = nullptr ;
2021-08-23 02:41:33 +00:00
2024-05-05 21:31:42 +00:00
vd_ref = nullptr ;
2021-08-15 20:07:12 +00:00
2024-05-06 19:47:13 +00:00
// parse the variable descripiton and create a var_desc_t record
2024-09-16 17:43:52 +00:00
if ( ( rc = _parse_class_var_cfg ( p , udpClassDesc , varDescPair , var_desc ) ) ! = kOkRC )
2021-08-15 20:07:12 +00:00
{
2024-05-05 21:31:42 +00:00
goto errLabel ;
2021-08-15 20:07:12 +00:00
}
2024-05-06 19:47:13 +00:00
if ( var_desc - > type ! = 0 )
2021-08-15 20:07:12 +00:00
{
2024-09-16 17:43:52 +00:00
cwLogWarning ( " The 'type' field int the variable description '%s' on the class description '%s' will be ignored because the variable is proxied. " , cwStringNullGuard ( udpClassDesc - > label ) , cwStringNullGuard ( var_desc - > label ) ) ;
2021-08-15 20:07:12 +00:00
}
2024-05-06 19:47:13 +00:00
// verify that a proxy-proc-label and proxy-var-label were specified in the variable descripiton
if ( var_desc - > proxyProcLabel = = nullptr | | var_desc - > proxyVarLabel = = nullptr )
2021-08-15 20:07:12 +00:00
{
2024-09-16 17:43:52 +00:00
rc = cwLogError ( kSyntaxErrorRC , " The UDP variable description '%s' in the UDP '%s' must have a valid 'proxy' field. " , cwStringNullGuard ( var_desc - > label ) , cwStringNullGuard ( udpClassDesc - > label ) ) ;
2024-05-05 21:31:42 +00:00
goto errLabel ;
2021-08-23 02:41:33 +00:00
}
2024-02-08 16:17:26 +00:00
2024-05-05 21:31:42 +00:00
// locate the class desc associated with proxy proc
2024-09-16 17:43:52 +00:00
if ( ( rc = _find_udp_proc_class_desc ( p , udpProcD , var_desc - > proxyProcLabel , proxy_class_desc ) ) ! = kOkRC )
2024-02-08 16:17:26 +00:00
{
goto errLabel ;
}
2024-05-05 21:31:42 +00:00
// locate the var desc associated with the proxy proc var
2024-05-06 19:47:13 +00:00
if ( ( proxy_var_desc = var_desc_find ( proxy_class_desc , var_desc - > proxyVarLabel ) ) = = nullptr )
2024-02-08 16:17:26 +00:00
{
2024-09-16 17:43:52 +00:00
rc = cwLogError ( kEleNotFoundRC , " The UDP proxied variable desc '%s.%s' could not be found in UDP '%s'. " , cwStringNullGuard ( var_desc - > proxyProcLabel ) , cwStringNullGuard ( var_desc - > proxyVarLabel ) , cwStringNullGuard ( udpClassDesc - > label ) ) ;
2024-05-05 21:31:42 +00:00
goto errLabel ;
2024-02-08 16:17:26 +00:00
}
2024-09-16 17:43:52 +00:00
// get the UDP var_desc type from the proxied var_desc
2024-05-06 19:47:13 +00:00
var_desc - > type = proxy_var_desc - > type ;
2024-05-05 21:31:42 +00:00
2024-09-16 17:43:52 +00:00
// augment the udp var_desc flags from the proxied var_desc
2024-05-06 19:47:13 +00:00
var_desc - > flags | = proxy_var_desc - > flags ;
2024-09-16 17:43:52 +00:00
// if no default value was given to the UDP var desc then get it from the proxied var desc
2024-05-06 19:47:13 +00:00
if ( var_desc - > val_cfg = = nullptr )
var_desc - > val_cfg = proxy_var_desc - > val_cfg ;
2024-05-05 21:31:42 +00:00
vd_ref = var_desc ;
2024-02-08 16:17:26 +00:00
errLabel :
2024-05-05 21:31:42 +00:00
if ( rc ! = kOkRC )
{
2024-05-06 19:47:13 +00:00
rc = cwLogError ( rc , " The creation of proxy var '%s' failed. " , var_desc = = nullptr ? " <unknown> " : cwStringNullGuard ( var_desc - > label ) ) ;
var_desc_destroy ( var_desc ) ;
2024-05-05 21:31:42 +00:00
}
2024-02-08 16:17:26 +00:00
return rc ;
}
2024-09-16 17:43:52 +00:00
rc_t _parse_udp_vars ( flow_t * p , class_desc_t * class_desc , const object_t * udpProcD , const object_t * varD )
2021-08-23 02:41:33 +00:00
{
rc_t rc = kOkRC ;
2024-05-05 21:31:42 +00:00
unsigned varN = 0 ;
2021-08-23 02:41:33 +00:00
2024-05-05 21:31:42 +00:00
if ( ! varD - > is_dict ( ) )
2021-08-23 02:41:33 +00:00
{
2024-05-05 21:31:42 +00:00
rc = cwLogError ( kSyntaxErrorRC , " The proxy variable dictionary is invalid. " ) ;
2021-08-23 02:41:33 +00:00
goto errLabel ;
}
2021-08-15 20:07:12 +00:00
2024-05-05 21:31:42 +00:00
varN = varD - > child_count ( ) ;
2021-08-23 02:41:33 +00:00
2024-09-16 17:43:52 +00:00
// Fill the class_Desc.varDescL list from the UDP 'vars' dictioanry
2024-05-05 21:31:42 +00:00
for ( unsigned i = 0 ; i < varN ; + + i )
2021-08-23 02:41:33 +00:00
{
2024-05-05 21:31:42 +00:00
const object_t * child_pair = varD - > child_ele ( i ) ;
var_desc_t * var_desc = nullptr ;
2024-09-16 17:43:52 +00:00
if ( ( rc = _create_udp_var_desc ( p , class_desc , udpProcD , child_pair , var_desc ) ) ! = kOkRC )
2024-02-08 16:17:26 +00:00
goto errLabel ;
2024-05-05 21:31:42 +00:00
var_desc - > link = class_desc - > varDescL ;
class_desc - > varDescL = var_desc ;
//printf("Wrapper var-desc created: %i of %i : %s:%s proxy:%s:%s flags:%i.\n", i, varN, class_desc->label, var_desc->label, var_desc->proxyProcLabel,var_desc->proxyVarLabel,var_desc->flags);
2024-02-08 16:17:26 +00:00
}
errLabel :
return rc ;
}
2024-09-16 17:43:52 +00:00
rc_t _create_udp_class_desc ( flow_t * p , const object_t * class_obj , class_desc_t * class_desc )
2024-02-08 16:17:26 +00:00
{
2024-05-05 21:31:42 +00:00
rc_t rc = kOkRC ;
const object_t * varD = nullptr ;
2024-09-16 17:43:52 +00:00
const object_t * udpD = nullptr ;
const object_t * udpProcD = nullptr ;
const object_t * udpPresetD = nullptr ;
const char * udpProcDescLabel = nullptr ;
2024-02-08 16:17:26 +00:00
2024-09-16 17:43:52 +00:00
// Validate the UDP proc desc label and value
if ( class_obj = = nullptr | | ! class_obj - > is_pair ( ) | | class_obj - > pair_value ( ) = = nullptr | | ! class_obj - > pair_value ( ) - > is_dict ( ) | | ( udpProcDescLabel = class_obj - > pair_label ( ) ) = = nullptr )
2024-02-08 16:17:26 +00:00
{
2024-09-16 17:43:52 +00:00
rc = cwLogError ( kInvalidArgRC , " An invalid UDP description '%s' was encountered. " , cwStringNullGuard ( udpProcDescLabel ) ) ;
2024-02-08 16:17:26 +00:00
goto errLabel ;
}
2024-09-16 17:43:52 +00:00
// verify that another UDP with the same name does not already exist
if ( class_desc_find ( p , udpProcDescLabel ) ! = nullptr )
2024-02-08 16:17:26 +00:00
{
2024-09-16 17:43:52 +00:00
rc = cwLogError ( kInvalidStateRC , " A UDP named '%s' already exists. " , udpProcDescLabel ) ;
2024-05-05 21:31:42 +00:00
goto errLabel ;
2024-02-08 16:17:26 +00:00
}
2024-05-05 21:31:42 +00:00
class_desc - > cfg = class_obj - > pair_value ( ) ;
class_desc - > label = class_obj - > pair_label ( ) ;
2024-09-16 17:43:52 +00:00
// get the 'UDP' members record
if ( ( class_desc - > members = _find_library_record ( " user_def_proc " ) ) = = nullptr )
2024-02-08 16:17:26 +00:00
{
2024-09-16 17:43:52 +00:00
rc = cwLogError ( kSyntaxErrorRC , " The 'UDP' class member function record could not be found. " ) ;
2024-05-05 21:31:42 +00:00
goto errLabel ;
2024-02-08 16:17:26 +00:00
}
2024-05-05 21:31:42 +00:00
// get the variable description
if ( ( rc = class_desc - > cfg - > getv_opt ( " vars " , varD ,
2024-09-16 17:43:52 +00:00
" network " , udpD ) ) ! = kOkRC )
2024-02-08 16:17:26 +00:00
{
2024-09-16 17:43:52 +00:00
rc = cwLogError ( rc , " Parse failed while parsing UDP desc:'%s' " , cwStringNullGuard ( class_desc - > label ) ) ;
2024-05-05 21:31:42 +00:00
goto errLabel ;
2024-02-08 16:17:26 +00:00
}
2024-09-16 17:43:52 +00:00
// get the UDP proc and preset dictionaries
if ( ( rc = udpD - > getv ( " procs " , udpProcD ,
" presets " , udpPresetD ) ) ! = kOkRC )
2024-02-08 16:17:26 +00:00
{
2024-05-05 21:31:42 +00:00
rc = cwLogError ( rc , " Parse failed on the 'network' element. " ) ;
2024-02-08 16:17:26 +00:00
goto errLabel ;
}
2024-09-16 17:43:52 +00:00
// fill class_desc.varDescL from the UDP vars dictionary
if ( ( rc = _parse_udp_vars ( p , class_desc , udpProcD , varD ) ) ! = kOkRC )
2024-05-05 21:31:42 +00:00
{
2024-09-16 17:43:52 +00:00
rc = cwLogError ( rc , " UDP 'vars' processing failed. " ) ;
2024-05-05 21:31:42 +00:00
goto errLabel ;
}
2021-08-23 02:41:33 +00:00
2024-02-08 16:17:26 +00:00
errLabel :
2024-05-05 21:31:42 +00:00
if ( rc ! = kOkRC )
2024-09-16 17:43:52 +00:00
rc = cwLogError ( rc , " 'proc' class description creation failed for the UDP '%s'. " , cwStringNullGuard ( udpProcDescLabel ) ) ;
2024-05-05 21:31:42 +00:00
2024-02-08 16:17:26 +00:00
return rc ;
}
2024-05-05 21:31:42 +00:00
2024-09-16 17:43:52 +00:00
rc_t _parse_udp_cfg ( flow_t * p , const object_t * udpCfg )
2024-02-08 16:17:26 +00:00
{
rc_t rc = kOkRC ;
2024-09-16 17:43:52 +00:00
if ( ! udpCfg - > is_dict ( ) )
return cwLogError ( kSyntaxErrorRC , " The UDP class description dictionary does not have dictionary syntax. " ) ;
2024-05-05 21:31:42 +00:00
2024-09-16 17:43:52 +00:00
unsigned udpDescN = udpCfg - > child_count ( ) ;
p - > udpDescA = mem : : allocZ < class_desc_t > ( udpDescN ) ;
2024-02-08 16:17:26 +00:00
2024-09-16 17:43:52 +00:00
// for each UDP description
for ( unsigned i = 0 ; i < udpDescN ; + + i )
2024-05-05 21:31:42 +00:00
{
2024-09-16 17:43:52 +00:00
const object_t * udp_obj = udpCfg - > child_ele ( i ) ;
2024-05-05 21:31:42 +00:00
2024-09-16 17:43:52 +00:00
if ( ( rc = _create_udp_class_desc ( p , udp_obj , p - > udpDescA + i ) ) ! = kOkRC )
2024-05-05 21:31:42 +00:00
{
2024-09-16 17:43:52 +00:00
rc = cwLogError ( rc , " UDP class description create failed on the UDP at index:%i. " , i ) ;
2024-02-08 16:17:26 +00:00
goto errLabel ;
2024-05-05 21:31:42 +00:00
}
2024-02-08 16:17:26 +00:00
2024-09-16 17:43:52 +00:00
// We have to update the size of the UDP class array
// as we go because we may want be able to search p->udpDescA[]
2024-05-06 19:47:13 +00:00
// aand to do that we must now the current length.
2024-09-16 17:43:52 +00:00
p - > udpDescN + = 1 ;
2024-05-05 21:31:42 +00:00
}
2021-08-23 02:41:33 +00:00
2024-09-16 17:43:52 +00:00
assert ( udpDescN = = p - > udpDescN ) ;
2024-02-08 16:17:26 +00:00
errLabel :
2024-05-05 21:31:42 +00:00
if ( rc ! = kOkRC )
{
2024-09-16 17:43:52 +00:00
rc = cwLogError ( rc , " UDP processing failed. " ) ;
2024-05-05 21:31:42 +00:00
}
2024-02-08 16:17:26 +00:00
return rc ;
2024-05-05 21:31:42 +00:00
2024-02-08 16:17:26 +00:00
}
2024-05-05 21:31:42 +00:00
2024-09-20 22:13:17 +00:00
rc_t _parse_preset_array ( flow_t * p , const object_t * netCfg )
{
rc_t rc = kOkRC ;
unsigned presetAllocN = 0 ;
const object_t * presetD = nullptr ;
if ( ( rc = netCfg - > getv_opt ( " presets " , presetD ) ) ! = kOkRC )
{
rc = cwLogError ( rc , " An error ocurred while locating the network 'presets' configuration. " ) ;
goto errLabel ;
}
// if this network does not have any presets
if ( presetD = = nullptr )
return rc ;
// the 'preset' cfg must be a dictionary
if ( ! presetD - > is_dict ( ) )
{
rc = cwLogError ( kSyntaxErrorRC , " The network preset list is not a dictionary. " ) ;
goto errLabel ;
}
presetAllocN = presetD - > child_count ( ) ;
p - > presetA = mem : : allocZ < network_preset_t > ( presetAllocN ) ;
p - > presetN = 0 ;
// parse each preset_label pair
for ( unsigned i = 0 ; i < presetAllocN ; + + i )
{
const object_t * preset_pair_cfg = presetD - > child_ele ( i ) ;
network_preset_t & network_preset = p - > presetA [ p - > presetN ] ;
// validate the network preset pair
if ( preset_pair_cfg = = nullptr | | ! preset_pair_cfg - > is_pair ( ) | | preset_pair_cfg - > pair_label ( ) = = nullptr | | preset_pair_cfg - > pair_value ( ) = = nullptr )
{
rc = cwLogError ( kSyntaxErrorRC , " Invalid syntax encountered on a network preset. " ) ;
goto errLabel ;
}
// get the preset type id
switch ( preset_pair_cfg - > pair_value ( ) - > type_id ( ) )
{
case kDictTId : // 'value-list' preset
network_preset . tid = kPresetVListTId ;
break ;
case kListTId : // dual preset
network_preset . tid = kPresetDualTId ;
break ;
default :
rc = cwLogError ( kAssertFailRC , " Unknown preset type on network preset: '%s'. " , cwStringNullGuard ( network_preset . label ) ) ;
goto errLabel ;
}
network_preset . label = preset_pair_cfg - > pair_label ( ) ;
p - > presetN + = 1 ;
}
errLabel :
if ( rc ! = kOkRC )
{
mem : : release ( p - > presetA ) ;
p - > presetN = 0 ;
}
2024-10-12 19:29:39 +00:00
return rc ;
2024-09-20 22:13:17 +00:00
}
2024-05-05 21:31:42 +00:00
void _release_class_desc_array ( class_desc_t * & classDescA , unsigned classDescN )
2024-02-08 16:17:26 +00:00
{
2024-04-22 20:02:40 +00:00
// release the class records
2024-05-05 21:31:42 +00:00
for ( unsigned i = 0 ; i < classDescN ; + + i )
2021-08-15 20:07:12 +00:00
{
2024-05-05 21:31:42 +00:00
class_desc_t * cd = classDescA + i ;
2024-05-06 19:47:13 +00:00
class_desc_destroy ( cd ) ;
2021-08-15 20:07:12 +00:00
}
2024-05-05 21:31:42 +00:00
mem : : release ( classDescA ) ;
2024-02-08 16:17:26 +00:00
}
2024-07-01 14:33:14 +00:00
rc_t _destroy ( flow_t * & p )
2024-02-08 16:17:26 +00:00
{
rc_t rc = kOkRC ;
2021-08-23 02:41:33 +00:00
2024-05-05 21:31:42 +00:00
if ( p = = nullptr )
return rc ;
2024-02-08 16:17:26 +00:00
2024-05-05 21:31:42 +00:00
network_destroy ( p - > net ) ;
2024-02-08 16:17:26 +00:00
2024-05-05 21:31:42 +00:00
_release_class_desc_array ( p - > classDescA , p - > classDescN ) ;
2024-09-16 17:43:52 +00:00
_release_class_desc_array ( p - > udpDescA , p - > udpDescN ) ;
2024-09-20 22:13:17 +00:00
mem : : release ( p - > presetA ) ;
p - > presetN = 0 ;
2024-07-01 14:33:14 +00:00
p - > classDescN = 0 ;
2024-09-16 17:43:52 +00:00
p - > udpDescN = 0 ;
2024-02-08 16:17:26 +00:00
2024-04-22 20:02:40 +00:00
mem : : release ( p ) ;
2024-02-08 16:17:26 +00:00
return rc ;
}
2021-08-23 02:41:33 +00:00
2024-10-14 18:20:13 +00:00
void _make_flow_to_ui_callback ( flow_t * p )
{
// There is no concurrent contention for the linked list when
// this function is called and so all accesses use relaxed memory order.
// Get the first variable to send to the UI
variable_t * var = p - > ui_var_tail - > ui_var_link . load ( std : : memory_order_relaxed ) ;
while ( var ! = nullptr )
{
// Send the var to the UI
if ( p - > ui_callback ! = nullptr )
p - > ui_callback ( p - > ui_callback_arg , var - > ui_var ) ;
// Get the next var to send to the UI
variable_t * var0 = var - > ui_var_link . load ( std : : memory_order_relaxed ) ;
// Nullify the list links as they are used
var - > ui_var_link . store ( nullptr , std : : memory_order_relaxed ) ;
var = var0 ;
}
// Empty the UI message list.
p - > ui_var_head . store ( & p - > ui_var_stub , std : : memory_order_relaxed ) ;
p - > ui_var_tail = & p - > ui_var_stub ;
p - > ui_var_stub . ui_var_link . store ( nullptr , std : : memory_order_relaxed ) ;
}
2021-08-15 20:07:12 +00:00
}
}
2021-12-19 17:10:35 +00:00
void cw : : flow : : print_abuf ( const abuf_t * abuf )
{
printf ( " Abuf: sr:%7.1f chs:%3i frameN:%4i %p " , abuf - > srate , abuf - > chN , abuf - > frameN , abuf - > buf ) ;
}
void cw : : flow : : print_external_device ( const external_device_t * dev )
{
2024-06-10 20:36:29 +00:00
cwLogPrint ( " Dev: %10s type:%3i fl:0x%x : " , cwStringNullGuard ( dev - > devLabel ) , dev - > typeId , dev - > flags ) ;
2021-12-19 17:10:35 +00:00
if ( dev - > typeId = = kAudioDevTypeId )
print_abuf ( dev - > u . a . abuf ) ;
2024-06-10 20:36:29 +00:00
cwLogPrint ( " \n " ) ;
2021-12-19 17:10:35 +00:00
}
2021-12-30 02:52:46 +00:00
2021-12-11 20:19:15 +00:00
cw : : rc_t cw : : flow : : create ( handle_t & hRef ,
2024-05-05 21:31:42 +00:00
const object_t * classCfg ,
2024-09-20 22:13:17 +00:00
const object_t * pgmCfg ,
2024-09-16 17:43:52 +00:00
const object_t * udpCfg ,
2024-10-14 18:20:13 +00:00
const char * proj_dir ,
ui_callback_t ui_callback ,
void * ui_callback_arg )
2021-08-15 20:07:12 +00:00
{
2021-12-11 20:19:15 +00:00
rc_t rc = kOkRC ;
bool printClassDictFl = false ;
2024-05-08 14:24:25 +00:00
unsigned maxCycleCount = kInvalidCnt ;
2024-05-29 23:31:22 +00:00
double durLimitSecs = 0 ;
2021-08-15 20:07:12 +00:00
if ( ( rc = destroy ( hRef ) ) ! = kOkRC )
return rc ;
flow_t * p = mem : : allocZ < flow_t > ( ) ;
// parse the class description array
2024-05-05 21:31:42 +00:00
if ( ( rc = _parse_class_cfg ( p , classCfg ) ) ! = kOkRC )
2021-08-15 20:07:12 +00:00
{
rc = cwLogError ( kSyntaxErrorRC , " Error parsing the class description list. " ) ;
goto errLabel ;
}
2024-09-16 17:43:52 +00:00
// parse the UDP descriptions
if ( udpCfg ! = nullptr )
if ( ( rc = _parse_udp_cfg ( p , udpCfg ) ) ! = kOkRC )
2024-05-05 21:31:42 +00:00
{
2024-09-16 17:43:52 +00:00
rc = cwLogError ( kSyntaxErrorRC , " Error parsing the UDP list. " ) ;
2024-05-05 21:31:42 +00:00
goto errLabel ;
}
2021-08-15 20:07:12 +00:00
2024-09-20 22:13:17 +00:00
p - > pgmCfg = pgmCfg ;
2024-05-02 17:59:19 +00:00
p - > framesPerCycle = kDefaultFramesPerCycle ;
p - > sample_rate = kDefaultSampleRate ;
2024-05-08 14:24:25 +00:00
p - > maxCycleCount = kInvalidCnt ;
2024-05-10 02:05:22 +00:00
p - > proj_dir = proj_dir ;
2024-09-12 21:18:42 +00:00
p - > printLogHdrFl = true ;
2024-10-14 18:20:13 +00:00
p - > ui_callback = ui_callback ;
p - > ui_callback_arg = ui_callback_arg ;
p - > ui_var_head . store ( & p - > ui_var_stub ) ;
p - > ui_var_tail = & p - > ui_var_stub ;
2024-05-08 14:24:25 +00:00
2021-08-23 02:41:33 +00:00
// parse the optional args
2024-09-20 22:13:17 +00:00
if ( ( rc = pgmCfg - > readv ( " network " , 0 , p - > networkCfg ,
2024-06-10 20:36:29 +00:00
" non_real_time_fl " , kOptFl , p - > non_real_time_fl ,
2024-09-12 21:18:42 +00:00
" frames_per_cycle " , kOptFl , p - > framesPerCycle ,
2024-05-29 23:31:22 +00:00
" sample_rate " , kOptFl , p - > sample_rate ,
2024-09-12 21:18:42 +00:00
" max_cycle_count " , kOptFl , maxCycleCount ,
" dur_limit_secs " , kOptFl , durLimitSecs ,
2024-05-29 23:31:22 +00:00
" preset " , kOptFl , p - > init_net_preset_label ,
2024-09-12 21:18:42 +00:00
" print_class_dict_fl " , kOptFl , printClassDictFl ,
" print_network_fl " , kOptFl , p - > printNetworkFl ,
2024-05-29 23:31:22 +00:00
" multiPriPresetProbFl " , kOptFl , p - > multiPriPresetProbFl ,
" multiSecPresetProbFl " , kOptFl , p - > multiSecPresetProbFl ,
" multiPresetInterpFl " , kOptFl , p - > multiPresetInterpFl ) ) ! = kOkRC )
2021-08-15 20:07:12 +00:00
{
2024-05-29 23:31:22 +00:00
rc = cwLogError ( kSyntaxErrorRC , " Error parsing the network system parameters. " ) ;
2021-08-15 20:07:12 +00:00
goto errLabel ;
}
2024-09-20 22:13:17 +00:00
if ( ( rc = _parse_preset_array ( p , p - > networkCfg ) ) ! = kOkRC )
{
rc = cwLogError ( rc , " Preset dictionary parsing failed. " ) ;
goto errLabel ;
}
2024-05-29 23:31:22 +00:00
// if a maxCycle count was given
2024-05-08 14:24:25 +00:00
if ( maxCycleCount ! = kInvalidCnt )
p - > maxCycleCount = maxCycleCount ;
2024-05-29 23:31:22 +00:00
else
{
// if a durLimitSecs was given - use it to setMaxCycleCount
if ( durLimitSecs ! = 0.0 )
p - > maxCycleCount = ( unsigned ) ( ( durLimitSecs * p - > sample_rate ) / p - > framesPerCycle ) ;
}
2024-05-08 14:24:25 +00:00
2024-06-11 00:40:41 +00:00
// print the class dict
if ( printClassDictFl )
class_dict_print ( p ) ;
hRef . set ( p ) ;
errLabel :
if ( rc ! = kOkRC )
_destroy ( p ) ;
return rc ;
}
2024-09-20 22:13:17 +00:00
bool cw : : flow : : is_non_real_time ( handle_t h )
{
flow_t * p = _handleToPtr ( h ) ;
return p - > non_real_time_fl ;
}
double cw : : flow : : sample_rate ( handle_t h )
{
flow_t * p = _handleToPtr ( h ) ;
return p - > sample_rate ;
}
unsigned cw : : flow : : frames_per_cycle ( handle_t h )
{
flow_t * p = _handleToPtr ( h ) ;
return p - > framesPerCycle ;
}
unsigned cw : : flow : : preset_count ( handle_t h )
{
flow_t * p = _handleToPtr ( h ) ;
return p - > presetN ;
}
const char * cw : : flow : : preset_label ( handle_t h , unsigned preset_idx )
{
flow_t * p = _handleToPtr ( h ) ;
if ( preset_idx > = p - > presetN )
{
2024-10-14 18:20:13 +00:00
cwLogError ( kInvalidArgRC , " The preset index %i is invalid. " , preset_idx ) ;
return nullptr ;
2024-09-20 22:13:17 +00:00
}
return p - > presetA [ preset_idx ] . label ;
}
unsigned cw : : flow : : preset_cfg_flags ( handle_t h )
{
flow_t * p = _handleToPtr ( h ) ;
unsigned flags = 0 ;
if ( p - > multiPriPresetProbFl )
flags | = kPriPresetProbFl ;
if ( p - > multiSecPresetProbFl )
flags | = kSecPresetProbFl ;
if ( p - > multiPresetInterpFl )
flags | = kInterpPresetFl ;
return flags ;
}
2024-06-11 00:40:41 +00:00
cw : : rc_t cw : : flow : : initialize ( handle_t h ,
external_device_t * deviceA ,
2024-09-20 22:13:17 +00:00
unsigned deviceN ,
2024-10-12 19:29:39 +00:00
unsigned preset_idx )
2024-06-11 00:40:41 +00:00
{
rc_t rc = kOkRC ;
variable_t * proxyVarL = nullptr ;
flow_t * p = _handleToPtr ( h ) ;
p - > deviceA = deviceA ;
p - > deviceN = deviceN ;
2024-04-22 20:02:40 +00:00
for ( unsigned i = 0 ; i < deviceN ; + + i )
if ( deviceA [ i ] . typeId = = kAudioDevTypeId )
2021-08-23 02:41:33 +00:00
{
2024-04-22 20:02:40 +00:00
if ( deviceA [ i ] . u . a . abuf = = NULL )
2021-08-23 02:41:33 +00:00
{
2024-04-22 20:02:40 +00:00
rc = cwLogError ( kInvalidArgRC , " The audio '%s' device does not have a valid audio buffer. " , cwStringNullGuard ( deviceA [ i ] . devLabel ) ) ;
2021-08-23 02:41:33 +00:00
goto errLabel ;
}
2024-04-22 20:02:40 +00:00
else
if ( deviceA [ i ] . u . a . abuf - > frameN ! = p - > framesPerCycle )
cwLogWarning ( " The audio frame count (%i) for audio device '%s' does not match the Flow framesPerCycle (%i). " , deviceA [ i ] . u . a . abuf - > frameN , p - > framesPerCycle ) ;
}
2024-09-20 22:13:17 +00:00
// if an initialization preset was given
if ( preset_idx ! = kInvalidIdx )
{
const char * preset_label_str ;
if ( ( preset_label_str = preset_label ( h , preset_idx ) ) = = nullptr )
{
cwLogError ( kInvalidArgRC , " The preset index '%i' could not be resolved to an existing preset. " ) ;
goto errLabel ;
}
// override the program assigned 'preset'
p - > init_net_preset_label = preset_label_str ;
}
2024-04-22 20:02:40 +00:00
// instantiate the network
2024-09-20 22:13:17 +00:00
if ( ( rc = network_create ( p , & p - > networkCfg , 1 , proxyVarL , 1 , p - > init_net_preset_label , p - > net ) ) ! = kOkRC )
2021-08-15 20:07:12 +00:00
{
2024-04-22 20:02:40 +00:00
rc = cwLogError ( rc , " Network creation failed. " ) ;
goto errLabel ;
2021-08-15 20:07:12 +00:00
}
2024-09-17 20:33:26 +00:00
if ( p - > printNetworkFl & & p - > net ! = nullptr )
network_print ( * p - > net ) ;
2024-02-08 16:17:26 +00:00
2024-09-20 22:13:17 +00:00
// The network preset may have been applied as each proc. was instantiated.
// This way any 'init' only preset values will have been applied and the
// proc's custom create is more likely to see the values from the preset.
// Now that the network is fully instantiated however we will apply it again
// to be sure that the final state of the network is determined by selected preset.
2024-09-17 20:33:26 +00:00
if ( p - > init_net_preset_label ! = nullptr & & p - > net ! = nullptr )
network_apply_preset ( * p - > net , p - > init_net_preset_label ) ;
2024-10-12 19:29:39 +00:00
// form the UI description
if ( ( rc = create_net_ui_desc ( p ) ) ! = kOkRC )
{
rc = cwLogError ( rc , " UI description formation failed. " ) ;
goto errLabel ;
}
2024-05-24 20:37:31 +00:00
2024-05-08 14:24:25 +00:00
p - > isInRuntimeFl = true ;
2024-05-24 20:37:31 +00:00
cwLogInfo ( " Entering runtime. " ) ;
2021-08-23 02:41:33 +00:00
2021-08-15 20:07:12 +00:00
errLabel :
2021-08-23 02:41:33 +00:00
2024-06-11 00:40:41 +00:00
return rc ;
2021-08-15 20:07:12 +00:00
}
2024-06-11 00:40:41 +00:00
2021-12-19 17:10:35 +00:00
cw : : rc_t cw : : flow : : destroy ( handle_t & hRef )
2021-12-11 20:19:15 +00:00
{
2021-12-19 17:10:35 +00:00
rc_t rc = kOkRC ;
flow_t * p = nullptr ; ;
if ( ! hRef . isValid ( ) )
return rc ;
p = _handleToPtr ( hRef ) ;
_destroy ( p ) ;
hRef . clear ( ) ;
return rc ;
2021-12-11 20:19:15 +00:00
}
2024-02-18 13:41:19 +00:00
2024-10-12 19:29:39 +00:00
const cw : : flow : : ui_net_t * cw : : flow : : ui_net ( handle_t h )
{
flow_t * p = _handleToPtr ( h ) ;
if ( p - > net = = nullptr )
{
cwLogError ( kInvalidStateRC , " No UI net exists because the no net exists. " ) ;
return nullptr ;
}
if ( p - > net - > ui_net = = nullptr )
return nullptr ;
return p - > net - > ui_net ;
}
2021-12-26 03:16:00 +00:00
cw : : rc_t cw : : flow : : exec_cycle ( handle_t h )
{
2024-07-04 21:02:45 +00:00
rc_t rc = kOkRC ; ;
flow_t * p = _handleToPtr ( h ) ;
if ( p - > maxCycleCount ! = kInvalidCnt & & p - > cycleIndex > = p - > maxCycleCount )
{
rc = kEofRC ;
cwLogInfo ( " 'maxCycleCnt' reached: %i. Shutting down flow. " , p - > maxCycleCount ) ;
}
else
{
2024-10-14 18:20:13 +00:00
// Execute one cycle of the network
if ( ( rc = exec_cycle ( * p - > net ) ) = = kOkRC )
{
// During network execution variables which need to update the UI
// are collected in a linked list based on p->ui_var_tail.
// Callback to the UI with those variables here.
_make_flow_to_ui_callback ( p ) ;
}
2024-07-04 21:02:45 +00:00
p - > cycleIndex + = 1 ;
}
2024-10-14 18:20:13 +00:00
2024-07-04 21:02:45 +00:00
return rc ;
2021-12-26 03:16:00 +00:00
}
cw : : rc_t cw : : flow : : exec ( handle_t h )
{
rc_t rc = kOkRC ;
2024-09-12 21:18:42 +00:00
//flow_t* p = _handleToPtr(h);
2021-12-26 03:16:00 +00:00
2024-07-04 21:02:45 +00:00
while ( rc = = kOkRC )
2024-09-12 21:18:42 +00:00
rc = exec_cycle ( h ) ;
2024-07-04 21:02:45 +00:00
2021-12-26 03:16:00 +00:00
return rc ;
}
2024-05-24 20:37:31 +00:00
2021-12-19 17:10:35 +00:00
cw : : rc_t cw : : flow : : apply_preset ( handle_t h , const char * presetLabel )
2021-08-15 20:07:12 +00:00
{
2021-12-19 17:10:35 +00:00
flow_t * p = _handleToPtr ( h ) ;
2024-09-17 20:33:26 +00:00
return network_apply_preset ( * p - > net , presetLabel ) ;
2021-12-19 17:10:35 +00:00
}
2024-02-08 16:17:26 +00:00
cw : : rc_t cw : : flow : : apply_dual_preset ( handle_t h , const char * presetLabel_0 , const char * presetLabel_1 , double coeff )
2024-01-13 15:16:37 +00:00
{
2024-02-08 16:17:26 +00:00
flow_t * p = _handleToPtr ( h ) ;
2024-09-17 20:33:26 +00:00
return network_apply_dual_preset ( * p - > net , presetLabel_0 , presetLabel_1 , coeff ) ;
2024-02-08 16:17:26 +00:00
}
2024-02-18 13:41:19 +00:00
cw : : rc_t cw : : flow : : apply_preset ( handle_t h , const multi_preset_selector_t & mps )
2024-02-08 16:17:26 +00:00
{
2024-04-22 20:02:40 +00:00
flow_t * p = _handleToPtr ( h ) ;
2024-09-17 20:33:26 +00:00
return network_apply_preset ( * p - > net , mps ) ;
2024-02-18 13:41:19 +00:00
}
2024-10-14 18:20:13 +00:00
cw : : rc_t cw : : flow : : set_variable_user_id ( handle_t h , const ui_var_t * ui_var , unsigned user_id )
{ return set_variable_user_id ( * _handleToPtr ( h ) - > net , ui_var , user_id ) ; }
2024-02-18 13:41:19 +00:00
2024-01-13 15:16:37 +00:00
2021-12-26 03:16:00 +00:00
cw : : rc_t cw : : flow : : set_variable_value ( handle_t h , const char * inst_label , const char * var_label , unsigned chIdx , bool value )
2024-09-17 20:33:26 +00:00
{ return set_variable_value ( * _handleToPtr ( h ) - > net , inst_label , var_label , chIdx , value ) ; }
2021-12-19 17:10:35 +00:00
2021-12-26 03:16:00 +00:00
cw : : rc_t cw : : flow : : set_variable_value ( handle_t h , const char * inst_label , const char * var_label , unsigned chIdx , int value )
2024-09-17 20:33:26 +00:00
{ return set_variable_value ( * _handleToPtr ( h ) - > net , inst_label , var_label , chIdx , value ) ; }
2021-12-26 03:16:00 +00:00
cw : : rc_t cw : : flow : : set_variable_value ( handle_t h , const char * inst_label , const char * var_label , unsigned chIdx , unsigned value )
2024-09-17 20:33:26 +00:00
{ return set_variable_value ( * _handleToPtr ( h ) - > net , inst_label , var_label , chIdx , value ) ; }
2021-12-26 03:16:00 +00:00
cw : : rc_t cw : : flow : : set_variable_value ( handle_t h , const char * inst_label , const char * var_label , unsigned chIdx , float value )
2024-09-17 20:33:26 +00:00
{ return set_variable_value ( * _handleToPtr ( h ) - > net , inst_label , var_label , chIdx , value ) ; }
2021-12-26 03:16:00 +00:00
cw : : rc_t cw : : flow : : set_variable_value ( handle_t h , const char * inst_label , const char * var_label , unsigned chIdx , double value )
2024-09-17 20:33:26 +00:00
{ return set_variable_value ( * _handleToPtr ( h ) - > net , inst_label , var_label , chIdx , value ) ; }
2021-08-15 20:07:12 +00:00
2023-01-05 12:26:25 +00:00
cw : : rc_t cw : : flow : : get_variable_value ( handle_t h , const char * inst_label , const char * var_label , unsigned chIdx , bool & valueRef )
2024-09-17 20:33:26 +00:00
{ return get_variable_value ( * _handleToPtr ( h ) - > net , inst_label , var_label , chIdx , valueRef ) ; }
2023-01-05 12:26:25 +00:00
cw : : rc_t cw : : flow : : get_variable_value ( handle_t h , const char * inst_label , const char * var_label , unsigned chIdx , int & valueRef )
2024-09-17 20:33:26 +00:00
{ return get_variable_value ( * _handleToPtr ( h ) - > net , inst_label , var_label , chIdx , valueRef ) ; }
2023-01-05 12:26:25 +00:00
cw : : rc_t cw : : flow : : get_variable_value ( handle_t h , const char * inst_label , const char * var_label , unsigned chIdx , unsigned & valueRef )
2024-09-17 20:33:26 +00:00
{ return get_variable_value ( * _handleToPtr ( h ) - > net , inst_label , var_label , chIdx , valueRef ) ; }
2023-01-05 12:26:25 +00:00
cw : : rc_t cw : : flow : : get_variable_value ( handle_t h , const char * inst_label , const char * var_label , unsigned chIdx , float & valueRef )
2024-09-17 20:33:26 +00:00
{ return get_variable_value ( * _handleToPtr ( h ) - > net , inst_label , var_label , chIdx , valueRef ) ; }
2023-01-05 12:26:25 +00:00
cw : : rc_t cw : : flow : : get_variable_value ( handle_t h , const char * inst_label , const char * var_label , unsigned chIdx , double & valueRef )
2024-09-17 20:33:26 +00:00
{ return get_variable_value ( * _handleToPtr ( h ) - > net , inst_label , var_label , chIdx , valueRef ) ; }
2023-01-05 12:26:25 +00:00
2024-10-12 19:29:39 +00:00
cw : : rc_t cw : : flow : : set_variable_value ( handle_t h , const ui_var_t * ui_var , bool value )
{ return set_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value ) ; }
cw : : rc_t cw : : flow : : set_variable_value ( handle_t h , const ui_var_t * ui_var , int value )
{ return set_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value ) ; }
cw : : rc_t cw : : flow : : set_variable_value ( handle_t h , const ui_var_t * ui_var , unsigned value )
{ return set_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value ) ; }
cw : : rc_t cw : : flow : : set_variable_value ( handle_t h , const ui_var_t * ui_var , float value )
{ return set_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value ) ; }
cw : : rc_t cw : : flow : : set_variable_value ( handle_t h , const ui_var_t * ui_var , double value )
{ return set_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value ) ; }
cw : : rc_t cw : : flow : : set_variable_value ( handle_t h , const ui_var_t * ui_var , const char * value )
{ return set_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value ) ; }
cw : : rc_t cw : : flow : : get_variable_value ( handle_t h , const ui_var_t * ui_var , bool & value_ref )
{ return get_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value_ref ) ; }
cw : : rc_t cw : : flow : : get_variable_value ( handle_t h , const ui_var_t * ui_var , int & value_ref )
{ return get_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value_ref ) ; }
cw : : rc_t cw : : flow : : get_variable_value ( handle_t h , const ui_var_t * ui_var , unsigned & value_ref )
{ return get_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value_ref ) ; }
cw : : rc_t cw : : flow : : get_variable_value ( handle_t h , const ui_var_t * ui_var , float & value_ref )
{ return get_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value_ref ) ; }
cw : : rc_t cw : : flow : : get_variable_value ( handle_t h , const ui_var_t * ui_var , double & value_ref )
{ return get_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value_ref ) ; }
cw : : rc_t cw : : flow : : get_variable_value ( handle_t h , const ui_var_t * ui_var , const char * & value_ref )
{ return get_variable_value ( * _handleToPtr ( h ) - > net , ui_var , value_ref ) ; }
2023-01-05 12:26:25 +00:00
2021-08-15 20:07:12 +00:00
2021-12-19 17:10:35 +00:00
void cw : : flow : : print_class_list ( handle_t h )
2021-08-15 20:07:12 +00:00
{
2021-12-19 17:10:35 +00:00
flow_t * p = _handleToPtr ( h ) ;
class_dict_print ( p ) ;
2021-08-15 20:07:12 +00:00
}
2021-12-19 17:10:35 +00:00
void cw : : flow : : print_network ( handle_t h )
2021-08-15 20:07:12 +00:00
{
2021-12-19 17:10:35 +00:00
flow_t * p = _handleToPtr ( h ) ;
for ( unsigned i = 0 ; i < p - > deviceN ; + + i )
print_external_device ( p - > deviceA + i ) ;
2024-09-17 20:33:26 +00:00
network_print ( * p - > net ) ;
2021-08-15 20:07:12 +00:00
}