#ifndef cwFlowValue_h #define cwFLowValue_h namespace cw { namespace flow { typedef dsp::coeff_t coeff_t; typedef dsp::sample_t sample_t; typedef dsp::fd_sample_t fd_sample_t; typedef dsp::srate_t srate_t; typedef dsp::ftime_t ftime_t; typedef unsigned uint_t; typedef int int_t; typedef unsigned vid_t; enum { kBaseSfxId = 0, kFbufVectN = 3, // count of signal vectors in fbuf (mag,phs,hz) kAnyChIdx = kInvalidIdx, kLocalValueN = 2, kDefaultFramesPerCycle=64, kDefaultSampleRate=48000 }; typedef struct abuf_str { srate_t srate; // Signal sample rate unsigned chN; // Count of channels unsigned frameN; // Count of sample frames per channel unsigned bufAllocSmpN; // Size of allocated buf[] in samples. sample_t* buf; // buf[ chN ][ frameN ] } abuf_t; typedef struct fbuf_str { unsigned memByteN; // Count of bytes in mem[]. void* mem; // mem[ memByteN ] All dynamically allocated memory used by this fbuf. srate_t srate; // signal sample rate unsigned flags; // See kXXXFbufFl unsigned chN; // count of channels unsigned* maxBinN_V; // maxBinN_V[chN] max value that binN_V[i] is allowed to take unsigned* binN_V; // binN_V[ chN ] count of sample frames per channel unsigned* hopSmpN_V; // hopSmpN_V[ chN ] hop sample count fd_sample_t** magV; // magV[ chN ][ binN ] fd_sample_t** phsV; // phsV[ chN ][ binN ] fd_sample_t** hzV; // hzV[ chN ][ binN ] bool* readyFlV; // readyFlV[chN] true if this channel is ready to be processed (used to sync. fbuf rate to abuf rate) } fbuf_t; typedef struct mbuf_str { const midi::ch_msg_t* msgA; unsigned msgN; } mbuf_t; enum { kInvalidTFl = 0x00000000, kBoolTFl = 0x00000001, kUIntTFl = 0x00000002, kIntTFl = 0x00000004, kFloatTFl = 0x00000008, kDoubleTFl = 0x00000010, kBoolMtxTFl = 0x00000020, kUIntMtxTFl = 0x00000040, kIntMtxTFl = 0x00000080, kFloatMtxTFl = 0x00000100, kDoubleMtxTFl= 0x00000200, kABufTFl = 0x00000400, kFBufTFl = 0x00000800, kMBufTFl = 0x00001000, kRBufTFl = 0x00002000, kStringTFl = 0x00004000, kTimeTFl = 0x00008000, kCfgTFl = 0x00010000, kMidiTFl = 0x00020000, kTypeMask = 0x0003ffff, kRuntimeTFl = 0x80000000, // The type of the value associated with this variable will be set by the proc instances during instantiation kNumericTFl = kBoolTFl | kUIntTFl | kIntTFl | kFloatTFl | kDoubleTFl, kMtxTFl = kBoolMtxTFl | kUIntMtxTFl | kIntMtxTFl | kFloatMtxTFl | kDoubleMtxTFl, kAllTFl = kTypeMask }; typedef struct mtx_str { union { struct mtx::mtx_str< unsigned >* u; struct mtx::mtx_str< int >* i; struct mtx::mtx_str< float >* f; struct mtx::mtx_str< double >* d; } u; } mtx_t; struct recd_type_str; struct recd_str; typedef struct rbuf_str { const struct recd_type_str* type; // all msgs are formed from this type const struct recd_str* recdA; // recdA[ recdN ] unsigned recdN; // } rbuf_t; typedef struct value_str { unsigned tflag; union { bool b; uint_t u; int_t i; float f; double d; mtx_t* mtx; abuf_t* abuf; fbuf_t* fbuf; mbuf_t* mbuf; rbuf_t* rbuf; char* s; const object_t* cfg; midi::ch_msg_t* midi; void* p; } u; struct value_str* link; } value_t; //------------------------------------------------------------------------------------------------------------------------ // // Value Only // inline void set_null( value_t& v, unsigned tflag ) { v.tflag=tflag; v.u.p=nullptr; } inline bool is_numeric( const value_t* v ) { return cwIsFlag(v->tflag,kNumericTFl); } inline bool is_matrix( const value_t* v ) { return cwIsFlag(v->tflag,kMtxTFl); } // if all of the src flags are set in the dst flags then the two types are convertable. inline bool can_convert( unsigned src_tflag, unsigned dst_tflag ) { return (src_tflag&dst_tflag)==src_tflag; } abuf_t* abuf_create( srate_t srate, unsigned chN, unsigned frameN ); void abuf_destroy( abuf_t*& buf ); // If 'dst' is null then a new abuf is allocated, filled with the contents of 'src'. // If 'dst' is non-null and there is enough space for the contents of 'src' then only a copy is executed. // If there is not enough space then dst is reallocated. abuf_t* abuf_duplicate( abuf_t* dst, const abuf_t* src ); rc_t abuf_set_channel( abuf_t* buf, unsigned chIdx, const sample_t* v, unsigned vN ); const sample_t* abuf_get_channel( abuf_t* buf, unsigned chIdx ); fbuf_t* fbuf_create( srate_t srate, unsigned chN, const unsigned* maxBinN_V, const unsigned* binN_V, const unsigned* hopSmpN_V, const fd_sample_t** magV=nullptr, const fd_sample_t** phsV=nullptr, const fd_sample_t** hzV=nullptr ); fbuf_t* fbuf_create( srate_t srate, unsigned chN, unsigned maxBinN, unsigned binN, unsigned hopSmpN, const fd_sample_t** magV=nullptr, const fd_sample_t** phsV=nullptr, const fd_sample_t** hzV=nullptr ); void fbuf_destroy( fbuf_t*& buf ); // Memory allocation will only occur if dst is null, or the size of dst's internal buffer are too small. fbuf_t* fbuf_duplicate( fbuf_t* dst, const fbuf_t* src ); mbuf_t* mbuf_create( const midi::ch_msg_t* msgA=nullptr, unsigned msgN=0 ); void mbuf_destroy( mbuf_t*& buf ); mbuf_t* mbuf_duplicate( const mbuf_t* src ); rbuf_t* rbuf_create( const struct recd_type_str* type=nullptr, const struct recd_str* recdA=nullptr, unsigned recdN=0 ); void rbuf_destroy( rbuf_t*& buf ); rbuf_t* rbuf_duplicate( const rbuf_t* src ); void rbuf_setup( rbuf_t* rbuf, struct recd_type_str* type, struct recd_str* recdA, unsigned recdN ); inline bool value_is_abuf( const value_t* v ) { return v->tflag & kABufTFl; } inline bool value_is_fbuf( const value_t* v ) { return v->tflag & kFBufTFl; } unsigned value_type_label_to_flag( const char* type_desc ); const char* value_type_flag_to_label( unsigned flag ); void value_release( value_t* v ); void value_duplicate( value_t& dst, const value_t& src ); // For all numeric types this function set's the type of 'value_ref' to the type of cfg. // For all other types sets the type of 'value_ref' to kCfgTFl and stores 'cfg' to value_ref.u.cfg; rc_t value_from_cfg( const object_t* cfg, value_t& value_ref ); // Assigns src to dst. If dst has a value type then src is converted to this type. // If the conversion is not possible then the function fail.s rc_t value_from_value( const value_t& src, value_t& dst ); void value_print( const value_t* value, bool info_fl=false); rc_t value_get( const value_t* val, bool& valRef ); rc_t value_set( value_t* val, bool v ); rc_t value_get( const value_t* val, uint_t& valRef ); rc_t value_set( value_t* val, uint_t v ); rc_t value_get( const value_t* val, int_t& valRef ); rc_t value_set( value_t* val, int_t v ); rc_t value_get( const value_t* val, float& valRef ); rc_t value_set( value_t* val, float v ); rc_t value_get( const value_t* val, double& valRef ); rc_t value_set( value_t* val, double v ); rc_t value_get( const value_t* val, const char*& valRef ); rc_t value_set( value_t* val, const char* v ); rc_t value_get( value_t* val, abuf_t*& valRef ); rc_t value_get( value_t* val, const abuf_t*& valRef ); rc_t value_set( value_t* val, abuf_t* v ); rc_t value_get( value_t* val, fbuf_t*& valRef ); rc_t value_get( value_t* val, const fbuf_t*& valRef ); rc_t value_set( value_t* val, fbuf_t* v ); rc_t value_get( value_t* val, mbuf_t*& valRef ); rc_t value_get( value_t* val, const mbuf_t*& valRef ); rc_t value_set( value_t* val, mbuf_t* v ); rc_t value_get( value_t* val, rbuf_t*& valRef ); rc_t value_get( value_t* val, const rbuf_t*& valRef ); rc_t value_set( value_t* val, rbuf_t* v ); rc_t value_get( value_t* val, const object_t*& valRef ); rc_t value_set( value_t* val, const object_t* v ); rc_t value_get( const value_t* val, midi::ch_msg_t*& valRef ); rc_t value_get( const value_t* val, const midi::ch_msg_t*& valRef ); rc_t value_set( value_t* val, midi::ch_msg_t* v ); //------------------------------------------------------------------------------------------------------------------------ // // Record // typedef struct recd_field_str { bool group_fl; // set if this field record is a group char* label; // field or group label value_t value; // default value for this field char* doc; // documentation field for this field union { unsigned index; // index into recd_t.valA of the value associated with this field struct recd_field_str* group_fieldL; } u; struct recd_field_str* link; } recd_field_t; typedef struct recd_type_str { recd_field_t* fieldL; // linked list of field spec's unsigned fieldN; // length of fieldL list (fieldN + base->fieldN) is total field count const struct recd_type_str* base; // base recd type that this field inherits from } recd_type_t; typedef struct recd_fmt_str { unsigned alloc_cnt; // count of records to pre-allocate recd_type_t* recd_type; // record type for this variable } recd_fmt_t; typedef struct recd_array_str { recd_type_t* type; // recd_type_t of this record array value_t* valA; // valA[ allocRecdN * type->fieldN ] struct recd_str* recdA; // recdA[ allocRecdN ] unsigned allocRecdN; // } recd_array_t; typedef struct recd_str { struct value_str* valA; // varA[ recd_type_t.fieldN ] array of field values const struct recd_str* base; // Pointer to the records inherited fields. } recd_t; // Create/destroy a recd_format_t object. rc_t recd_format_create( recd_fmt_t*& recd_fmt_ref, const object_t* cfg ); void recd_format_destroy( recd_fmt_t*& recd_fmt_ref ); // Create a recd_type_t instance from a cfg. description. rc_t recd_type_create( recd_type_t*& recd_type_ref, const recd_type_t* base_type, const object_t* cfg ); void recd_type_destroy( recd_type_t*& recd_type ); // Count of fields combined local and base record types. rc_t recd_type_max_field_count( const recd_type_t* recd_type ); // Get the field index associated with a named field. // Use '.' notation to separate groups from fields. // Note if this is a 'local' field then the high bit in the returned index will be set. unsigned recd_type_field_index( const recd_type_t* recd_type, const char* field_label); // Given a field index return the field label. const char* recd_type_field_index_to_label( const recd_type_t* recd_type, unsigned field_idx ); // Set the record base pointer and the value of all fields with default values. rc_t recd_init( const recd_type_t* recd_type, const recd_t* base, recd_t* r ); // Print the recd_type info. to the console. void recd_type_print( const recd_type_t* recd_type ); // Read the value from a single record field template< typename T > rc_t recd_get( const recd_type_t* type, const recd_t* recd, unsigned field_idx, T& val_ref ) { if( field_idx < type->fieldN ) return value_get( recd->valA + field_idx, val_ref ); return recd_get( type->base, recd->base, field_idx - type->fieldN, val_ref ); } inline rc_t _recd_get(const recd_type_t* recd_type, recd_t* r ) { return kOkRC; } template< typename T1, typename... ARGS > rc_t _recd_get( const recd_type_t* recd_type, const recd_t* recd, unsigned field_idx, T1& val, ARGS&&... args ) { rc_t rc = kOkRC; if((rc = recd_get(recd_type,recd,field_idx,val)) != kOkRC ) return rc; return _recd_get(recd_type,recd,std::forward(args)...); } // Read the value of multiple record fields. template< typename T1, typename... ARGS > rc_t recd_get( const recd_type_t* recd_type, const recd_t* recd, unsigned field_idx, T1& val, ARGS&&... args ) { return _recd_get(recd_type,recd,field_idx,val,args...); } // Set the base record pointer for a record with an inherited base inline rc_t recd_set_base( const recd_type_t* type, recd_t* recd, const recd_t* base ) { // if we are setting base then the type must have a base type assert( (type->base == nullptr && base==nullptr) || (type->base!=nullptr && base!=nullptr) ); recd->base = base; return kOkRC; } template< typename T > rc_t recd_set( const recd_type_t* type, const recd_t* base, recd_t* recd, unsigned field_idx, const T& val ) { if( field_idx >= type->fieldN ) return cwLogError(kInvalidArgRC,"Only 'local' record value may be set."); // set the base of this record recd_set_base(type,recd,base); return value_set( recd->valA + field_idx, val ); } inline rc_t _recd_set( const recd_type_t* recd_type, recd_t* recd ) { return kOkRC; } template< typename T1, typename... ARGS > rc_t _recd_set( const recd_type_t* recd_type, recd_t* recd, unsigned field_idx, const T1& val, ARGS&&... args ) { rc_t rc = kOkRC; if( field_idx >= recd_type->fieldN ) return cwLogError(kInvalidArgRC,"Fields in the inherited record may not be set."); if((rc = value_set( recd->valA + field_idx, val)) != kOkRC ) { rc = cwLogError(rc,"Field set failed on '%s'.", cwStringNullGuard(recd_type_field_index_to_label( recd_type, field_idx ))); goto errLabel; } return _recd_set(recd_type,recd,std::forward(args)...); errLabel: return rc; } // Set multiple fields of a record. template< typename T1, typename... ARGS > rc_t recd_set( const recd_type_t* recd_type, const recd_t* base, recd_t* recd, unsigned field_idx, const T1& val, ARGS&&... args ) { rc_t rc = kOkRC; if((rc = recd_init( recd_type, base, recd )) != kOkRC ) goto errLabel; if((rc = _recd_set(recd_type,recd,field_idx,val,args...)) != kOkRC ) goto errLabel; errLabel: return rc; } // Print a record to the console. rc_t recd_print( const recd_type_t* recd_type, const recd_t* r ); // Create/destroy a buffer of records. rc_t recd_array_create( recd_array_t*& recd_array_ref, recd_type_t* recd_type, const recd_type_t* base, unsigned allocRecdN ); rc_t recd_array_destroy( recd_array_t*& recd_array_ref ); rc_t value_test( const test::test_args_t& args ); } } #endif